diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index dd939620..ff261bad 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -3,7 +3,7 @@ FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT} USER vscode -RUN curl -sSf https://rye-up.com/get | RYE_VERSION="0.24.0" RYE_INSTALL_OPTION="--yes" bash +RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.44.0" RYE_INSTALL_OPTION="--yes" bash ENV PATH=/home/vscode/.rye/shims:$PATH -RUN echo "[[ -d .venv ]] && source .venv/bin/activate" >> /home/vscode/.bashrc +RUN echo "[[ -d .venv ]] && source .venv/bin/activate || export PATH=\$PATH" >> /home/vscode/.bashrc diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index bbeb30b1..c17fdc16 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -24,6 +24,9 @@ } } } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": {} } // Features to add to the dev container. More info: https://containers.dev/features. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0f300739..ab500977 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,40 +2,103 @@ name: CI on: push: branches: - - main + - '**' + - '!integrated/**' + - '!stl-preview-head/**' + - '!stl-preview-base/**' + - '!generated' + - '!codegen/**' + - 'codegen/stl/**' pull_request: - branches: - - main + branches-ignore: + - 'stl-preview-head/**' + - 'stl-preview-base/**' jobs: lint: + timeout-minutes: 10 name: lint - runs-on: ubuntu-latest - if: github.repository == 'orbcorp/orb-python' - + runs-on: ${{ github.repository == 'stainless-sdks/orb-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install Rye run: | - curl -sSf https://rye-up.com/get | bash + curl -sSf https://rye.astral.sh/get | bash echo "$HOME/.rye/shims" >> $GITHUB_PATH env: - RYE_VERSION: 0.24.0 - RYE_INSTALL_OPTION: "--yes" + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' - name: Install dependencies - run: | - rye sync --all-features + run: rye sync --all-features - - name: Run ruff - run: | - rye run check:ruff + - name: Run lints + run: ./scripts/lint + + build: + if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') + timeout-minutes: 10 + name: build + permissions: + contents: read + id-token: write + runs-on: ${{ github.repository == 'stainless-sdks/orb-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Run type checking + - name: Install Rye run: | - rye run typecheck + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Install dependencies + run: rye sync --all-features - - name: Ensure importable + - name: Run build + run: rye build + + - name: Get GitHub OIDC Token + if: |- + github.repository == 'stainless-sdks/orb-python' && + !startsWith(github.ref, 'refs/heads/stl/') + id: github-oidc + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + script: core.setOutput('github_token', await core.getIDToken()); + + - name: Upload tarball + if: |- + github.repository == 'stainless-sdks/orb-python' && + !startsWith(github.ref, 'refs/heads/stl/') + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + run: ./scripts/utils/upload-artifact.sh + + test: + timeout-minutes: 10 + name: test + runs-on: ${{ github.repository == 'stainless-sdks/orb-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Install Rye run: | - rye run python -c 'import orb' + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Bootstrap + run: ./scripts/bootstrap + + - name: Run tests + run: ./scripts/test diff --git a/.github/workflows/create_asana_task.yaml b/.github/workflows/create_asana_task.yaml deleted file mode 100644 index d3ef6e7d..00000000 --- a/.github/workflows/create_asana_task.yaml +++ /dev/null @@ -1,24 +0,0 @@ -name: Asana -on: - issues: - types: [opened] - -jobs: - create_task: - name: Create Asana task - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - uses: orbcorp/gha-create-asana-task@main - with: - asana-secret: ${{ secrets.ASANA_PAT }} - asana-project-id: ${{ secrets.ASANA_PROJECT_ID }} - asana-workspace-id: ${{ secrets.ASANA_WORKSPACE_ID }} - asana-task-name: ${{ github.event.issue.title }} - asana-task-description: ${{ github.event.issue.body }} - asana-custom-fields: |- - { - "1205809189288915": "1205809189288916", - "1205809189288926": "${{ github.event.issue.html_url }}" - } diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 2a3f9b8f..0abeb7a7 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -14,15 +14,15 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install Rye run: | - curl -sSf https://rye-up.com/get | bash + curl -sSf https://rye.astral.sh/get | bash echo "$HOME/.rye/shims" >> $GITHUB_PATH env: - RYE_VERSION: 0.24.0 - RYE_INSTALL_OPTION: "--yes" + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' - name: Publish to PyPI run: | diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index a55199c6..d0b7ff53 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -1,6 +1,8 @@ name: Release Doctor on: pull_request: + branches: + - main workflow_dispatch: jobs: @@ -10,7 +12,7 @@ jobs: if: github.repository == 'orbcorp/orb-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Check release environment run: | diff --git a/.gitignore b/.gitignore index a4b2f8c0..3824f4c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -.vscode +.prism.log +.stdy.log _dev __pycache__ @@ -12,3 +13,4 @@ dist .env .envrc codegen.log +Brewfile.lock.json diff --git a/.release-please-manifest.json b/.release-please-manifest.json index fea051a9..ec0f76b7 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.47.1" + ".": "4.55.2" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 6211a376..4583110f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1,4 @@ -configured_endpoints: 81 +configured_endpoints: 139 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb/orb-2fa2fb8f97c2d358b6f022c3f92b56f14bb934197b043b01ee55640ae862898c.yml +openapi_spec_hash: 08569b240aaff4a6b0a054b734fc7ca9 +config_hash: c01c1191b1cd696c7ca855ff6d28a8df diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..5b010307 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.analysis.importFormat": "relative", +} diff --git a/Brewfile b/Brewfile new file mode 100644 index 00000000..492ca37b --- /dev/null +++ b/Brewfile @@ -0,0 +1,2 @@ +brew "rye" + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bc628536..13aed782 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,9 +2,13 @@ ### With Rye -We use [Rye](https://rye-up.com/) to manage dependencies so we highly recommend [installing it](https://rye-up.com/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 @@ -13,8 +17,7 @@ $ rye sync --all-features You can then run scripts using `rye run python script.py` or by activating the virtual environment: ```sh -$ rye shell -# or manually activate - https://docs.python.org/3/library/venv.html#how-venvs-work +# Activate the virtual environment - https://docs.python.org/3/library/venv.html#how-venvs-work $ source .venv/bin/activate # now you can omit the `rye run` prefix @@ -31,25 +34,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 +61,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 +71,28 @@ 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. +Most tests require you to [set up a mock server](https://github.com/dgellow/steady) against the OpenAPI spec to run the tests. -```bash -# you will need npm installed -npx prism mock path/to/your/openapi.yml +```sh +$ ./scripts/mock ``` -```bash -rye run pytest +```sh +$ ./scripts/test ``` ## Linting and formatting @@ -100,14 +102,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/LICENSE b/LICENSE index 782200ee..7434159e 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2024 Orb + Copyright 2026 Orb Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index ed7f738a..0ca679c9 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,15 @@ # Orb Python API library -[![PyPI version](https://img.shields.io/pypi/v/orb-billing.svg)](https://pypi.org/project/orb-billing/) + +[![PyPI version](https://img.shields.io/pypi/v/orb-billing.svg?label=pypi%20(stable))](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.9+ 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). ## Documentation -The REST API documentation can be found [on docs.withorb.com](https://docs.withorb.com/reference/api-reference). The full API of this library can be found in [api.md](api.md). +The REST API documentation can be found on [docs.withorb.com](https://docs.withorb.com/reference/api-reference). The full API of this library can be found in [api.md](api.md). ## Installation @@ -26,8 +27,7 @@ import os from orb import Orb client = Orb( - # This is the default and can be omitted - api_key=os.environ.get("ORB_API_KEY"), + api_key=os.environ.get("ORB_API_KEY"), # This is the default and can be omitted ) customer = client.customers.create( @@ -52,8 +52,7 @@ import asyncio from orb import AsyncOrb client = AsyncOrb( - # This is the default and can be omitted - api_key=os.environ.get("ORB_API_KEY"), + api_key=os.environ.get("ORB_API_KEY"), # This is the default and can be omitted ) @@ -70,12 +69,47 @@ asyncio.run(main()) Functionality between the synchronous and asynchronous clients is otherwise identical. +### With aiohttp + +By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend. + +You can enable this by installing `aiohttp`: + +```sh +# install from PyPI +pip install orb-billing[aiohttp] +``` + +Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: + +```python +import os +import asyncio +from orb import DefaultAioHttpClient +from orb import AsyncOrb + + +async def main() -> None: + async with AsyncOrb( + api_key=os.environ.get("ORB_API_KEY"), # This is the default and can be omitted + http_client=DefaultAioHttpClient(), + ) as client: + customer = await client.customers.create( + email="example-customer@withorb.com", + name="My Customer", + ) + print(customer.id) + + +asyncio.run(main()) +``` + ## Using types -Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev), which provide helper methods for things like: +Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like: -- Serializing back into JSON, `model.model_dump_json(indent=2, exclude_unset=True)` -- Converting to a dictionary, `model.model_dump(exclude_unset=True)` +- Serializing back into JSON, `model.to_json()` +- Converting to a dictionary, `model.to_dict()` Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`. @@ -86,7 +120,7 @@ List methods in the Orb API are paginated. This library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually: ```python -import orb +from orb import Orb client = Orb() @@ -102,7 +136,7 @@ Or, asynchronously: ```python import asyncio -import orb +from orb import AsyncOrb client = AsyncOrb() @@ -196,7 +230,7 @@ except orb.APIStatusError as e: print(e.response) ``` -Error codes are as followed: +Error codes are as follows: | Status Code | Error Type | | ----------- | -------------------------- | @@ -236,7 +270,7 @@ client.with_options(max_retries=5).customers.create( ### Timeouts By default requests time out after 1 minute. You can configure this with a `timeout` option, -which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object: +which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object: ```python from orb import Orb @@ -253,7 +287,7 @@ client = Orb( ) # Override per-request: -client.with_options(timeout=5 * 1000).customers.create( +client.with_options(timeout=5.0).customers.create( email="example-customer@withorb.com", name="My Customer", ) @@ -269,12 +303,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`: @@ -305,7 +341,7 @@ customer = response.parse() # get the object that `customers.create()` would ha print(customer.id) ``` -These methods return an [`LegacyAPIResponse`](https://github.com/orbcorp/orb-python/tree/main/src/orb/_legacy_response.py) object. This is a legacy class as we're changing it slightly in the next major version. +These methods return a [`LegacyAPIResponse`](https://github.com/orbcorp/orb-python/tree/main/src/orb/_legacy_response.py) object. This is a legacy class as we're changing it slightly in the next major version. For the sync client this will mostly be the same with the exception of `content` & `text` will be methods instead of properties. In the @@ -337,15 +373,14 @@ The context manager is required so that the response will reliably be closed. ### Making custom/undocumented requests -This library is typed for convenient access the documented API. +This library is typed for convenient access to the documented API. If you need to access undocumented endpoints, params, or response properties, the library can still be used. #### Undocumented endpoints To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other -http verbs. Options on the client will be respected (such as retries) will be respected when making this -request. +http verbs. Options on the client will be respected (such as retries) when making this request. ```py import httpx @@ -359,12 +394,12 @@ response = client.post( print(response.headers.get("x-foo")) ``` -#### Undocumented params +#### Undocumented request params If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request options. -#### Undocumented properties +#### Undocumented response properties To access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You can also get all the extra fields on the Pydantic model as a dict with @@ -374,40 +409,71 @@ can also get all the extra fields on the Pydantic model as a dict with You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including: -- Support for proxies -- Custom transports -- Additional [advanced](https://www.python-httpx.org/advanced/#client-instances) functionality +- Support for [proxies](https://www.python-httpx.org/advanced/proxies/) +- Custom [transports](https://www.python-httpx.org/advanced/transports/) +- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality ```python import httpx -from orb import Orb +from orb import Orb, DefaultHttpxClient client = Orb( # Or use the `ORB_BASE_URL` env var base_url="http://my.test.server.example.com:8083", - http_client=httpx.Client( - proxies="http://my.test.proxy.example.com", + http_client=DefaultHttpxClient( + proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0"), ), ) ``` +You can also customize the client on a per-request basis by using `with_options()`: + +```python +client.with_options(http_client=DefaultHttpxClient(...)) +``` + ### Managing HTTP resources By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting. +```py +from orb import Orb + +with Orb() as client: + # make requests here + ... + +# HTTP client is now closed +``` + ## Versioning This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: 1. Changes that only affect static types, without breaking runtime behavior. -2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals)_. +2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ 3. Changes that we do not expect to impact the vast majority of users in practice. We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. 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.9 or higher. + +## Contributing + +See [the contributing documentation](./CONTRIBUTING.md). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..3011c342 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,27 @@ +# Security Policy + +## Reporting Security Issues + +This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. + +To report a security issue, please contact the Stainless team at security@stainless.com. + +## Responsible Disclosure + +We appreciate the efforts of security researchers and individuals who help us maintain the security of +SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible +disclosure practices by allowing us a reasonable amount of time to investigate and address the issue +before making any information public. + +## Reporting Non-SDK Related Security Issues + +If you encounter security issues that are not directly related to SDKs but pertain to the services +or products provided by Orb, please follow the respective company's security reporting guidelines. + +### Orb Terms and Policies + +Please contact team@withorb.com for any questions or concerns regarding the security of our services. + +--- + +Thank you for helping us keep the SDKs and systems they interact with secure. diff --git a/api.md b/api.md index 7cb76d98..1d9ebf9b 100644 --- a/api.md +++ b/api.md @@ -1,7 +1,138 @@ # Shared Types ```python -from orb.types import Discount +from orb.types import ( + Address, + AdjustmentInterval, + AggregatedCost, + Allocation, + AmountDiscount, + AmountDiscountInterval, + BillableMetricTiny, + BillingCycleAnchorConfiguration, + BillingCycleConfiguration, + BillingCycleRelativeDate, + BulkConfig, + BulkTier, + ChangedSubscriptionResources, + ConversionRateTier, + ConversionRateTieredConfig, + ConversionRateUnitConfig, + CouponRedemption, + CreditNote, + CreditNoteTiny, + CustomExpiration, + CustomerMinified, + CustomerTaxID, + DimensionalPriceConfiguration, + Discount, + FixedFeeQuantityScheduleEntry, + FixedFeeQuantityTransition, + Invoice, + InvoiceLevelDiscount, + InvoiceTiny, + ItemSlim, + MatrixConfig, + MatrixSubLineItem, + MatrixValue, + MatrixWithAllocationConfig, + Maximum, + MaximumInterval, + Minimum, + MinimumInterval, + MonetaryAmountDiscountAdjustment, + MonetaryMaximumAdjustment, + MonetaryMinimumAdjustment, + MonetaryPercentageDiscountAdjustment, + MonetaryUsageDiscountAdjustment, + NewAllocationPrice, + NewAmountDiscount, + NewBillingCycleConfiguration, + NewDimensionalPriceConfiguration, + NewFloatingBulkPrice, + NewFloatingBulkWithProrationPrice, + NewFloatingCumulativeGroupedBulkPrice, + NewFloatingGroupedAllocationPrice, + NewFloatingGroupedTieredPackagePrice, + NewFloatingGroupedTieredPrice, + NewFloatingGroupedWithMeteredMinimumPrice, + NewFloatingGroupedWithProratedMinimumPrice, + NewFloatingMatrixPrice, + NewFloatingMatrixWithAllocationPrice, + NewFloatingMatrixWithDisplayNamePrice, + NewFloatingMaxGroupTieredPackagePrice, + NewFloatingMinimumCompositePrice, + NewFloatingPackagePrice, + NewFloatingPackageWithAllocationPrice, + NewFloatingScalableMatrixWithTieredPricingPrice, + NewFloatingScalableMatrixWithUnitPricingPrice, + NewFloatingThresholdTotalAmountPrice, + NewFloatingTieredPackagePrice, + NewFloatingTieredPackageWithMinimumPrice, + NewFloatingTieredPrice, + NewFloatingTieredWithMinimumPrice, + NewFloatingTieredWithProrationPrice, + NewFloatingUnitPrice, + NewFloatingUnitWithPercentPrice, + NewFloatingUnitWithProrationPrice, + NewMaximum, + NewMinimum, + NewPercentageDiscount, + NewPlanBulkPrice, + NewPlanBulkWithProrationPrice, + NewPlanCumulativeGroupedBulkPrice, + NewPlanGroupedAllocationPrice, + NewPlanGroupedTieredPackagePrice, + NewPlanGroupedTieredPrice, + NewPlanGroupedWithMeteredMinimumPrice, + NewPlanGroupedWithProratedMinimumPrice, + NewPlanMatrixPrice, + NewPlanMatrixWithAllocationPrice, + NewPlanMatrixWithDisplayNamePrice, + NewPlanMaxGroupTieredPackagePrice, + NewPlanMinimumCompositePrice, + NewPlanPackagePrice, + NewPlanPackageWithAllocationPrice, + NewPlanScalableMatrixWithTieredPricingPrice, + NewPlanScalableMatrixWithUnitPricingPrice, + NewPlanThresholdTotalAmountPrice, + NewPlanTieredPackagePrice, + NewPlanTieredPackageWithMinimumPrice, + NewPlanTieredPrice, + NewPlanTieredWithMinimumPrice, + NewPlanUnitPrice, + NewPlanUnitWithPercentPrice, + NewPlanUnitWithProrationPrice, + NewUsageDiscount, + OtherSubLineItem, + PackageConfig, + PaginationMetadata, + PerPriceCost, + PercentageDiscount, + PercentageDiscountInterval, + PlanPhaseAmountDiscountAdjustment, + PlanPhaseMaximumAdjustment, + PlanPhaseMinimumAdjustment, + PlanPhasePercentageDiscountAdjustment, + PlanPhaseUsageDiscountAdjustment, + Price, + PriceInterval, + SubLineItemGrouping, + SubLineItemMatrixConfig, + SubscriptionChangeMinified, + SubscriptionMinified, + SubscriptionTrialInfo, + TaxAmount, + Tier, + TierSubLineItem, + TieredConfig, + TieredConversionRateConfig, + TrialDiscount, + UnitConfig, + UnitConversionRateConfig, + UsageDiscount, + UsageDiscountInterval, +) ``` # TopLevel @@ -16,6 +147,28 @@ Methods: - client.top_level.ping() -> TopLevelPingResponse +# Beta + +Types: + +```python +from orb.types import PlanVersion, PlanVersionPhase +``` + +Methods: + +- client.beta.create_plan_version(plan_id, \*\*params) -> PlanVersion +- client.beta.fetch_plan_version(version, \*, plan_id) -> PlanVersion +- client.beta.set_default_plan_version(plan_id, \*\*params) -> Plan + +## ExternalPlanID + +Methods: + +- client.beta.external_plan_id.create_plan_version(external_plan_id, \*\*params) -> PlanVersion +- client.beta.external_plan_id.fetch_plan_version(version, \*, external_plan_id) -> PlanVersion +- client.beta.external_plan_id.set_default_plan_version(external_plan_id, \*\*params) -> Plan + # Coupons Types: @@ -39,23 +192,28 @@ Methods: # CreditNotes -Types: - -```python -from orb.types import CreditNote -``` - Methods: -- client.credit_notes.list(\*\*params) -> SyncPage[CreditNote] -- client.credit_notes.fetch(credit_note_id) -> CreditNote +- client.credit_notes.create(\*\*params) -> CreditNote +- client.credit_notes.list(\*\*params) -> SyncPage[CreditNote] +- client.credit_notes.fetch(credit_note_id) -> CreditNote # Customers Types: ```python -from orb.types import Customer +from orb.types import ( + AccountingProviderConfig, + AddressInput, + Customer, + CustomerHierarchyConfig, + NewAccountingSyncConfiguration, + NewAvalaraTaxConfiguration, + NewReportingConfiguration, + NewSphereConfiguration, + NewTaxJarConfiguration, +) ``` Methods: @@ -66,6 +224,8 @@ Methods: - client.customers.delete(customer_id) -> None - client.customers.fetch(customer_id) -> Customer - client.customers.fetch_by_external_id(external_customer_id) -> Customer +- client.customers.sync_payment_methods_from_gateway(customer_id) -> None +- client.customers.sync_payment_methods_from_gateway_by_external_customer_id(external_customer_id) -> None - client.customers.update_by_external_id(id, \*\*params) -> Customer ## Costs @@ -81,19 +241,6 @@ Methods: - client.customers.costs.list(customer_id, \*\*params) -> CostListResponse - client.customers.costs.list_by_external_id(external_customer_id, \*\*params) -> CostListByExternalIDResponse -## Usage - -Types: - -```python -from orb.types.customers import UsageUpdateResponse, UsageUpdateByExternalIDResponse -``` - -Methods: - -- client.customers.usage.update(id, \*\*params) -> UsageUpdateResponse -- client.customers.usage.update_by_external_id(id, \*\*params) -> UsageUpdateByExternalIDResponse - ## Credits Types: @@ -113,6 +260,14 @@ Types: ```python from orb.types.customers.credits import ( + AffectedBlock, + AmendmentLedgerEntry, + CreditBlockExpiryLedgerEntry, + DecrementLedgerEntry, + ExpirationChangeLedgerEntry, + IncrementLedgerEntry, + VoidInitiatedLedgerEntry, + VoidLedgerEntry, LedgerListResponse, LedgerCreateEntryResponse, LedgerCreateEntryByExternalIDResponse, @@ -133,6 +288,7 @@ Types: ```python from orb.types.customers.credits import ( + TopUpInvoiceSettings, TopUpCreateResponse, TopUpListResponse, TopUpCreateByExternalIDResponse, @@ -204,6 +360,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: @@ -221,18 +389,27 @@ Methods: Types: ```python -from orb.types import Invoice, InvoiceFetchUpcomingResponse +from orb.types import ( + InvoiceFetchUpcomingResponse, + InvoiceIssueSummaryResponse, + InvoiceListSummaryResponse, +) ``` Methods: -- client.invoices.create(\*\*params) -> Invoice -- client.invoices.list(\*\*params) -> SyncPage[Invoice] -- client.invoices.fetch(invoice_id) -> Invoice +- client.invoices.create(\*\*params) -> Invoice +- client.invoices.update(invoice_id, \*\*params) -> Invoice +- client.invoices.list(\*\*params) -> SyncPage[Invoice] +- client.invoices.delete_line_item(line_item_id, \*, invoice_id) -> None +- client.invoices.fetch(invoice_id) -> Invoice - client.invoices.fetch_upcoming(\*\*params) -> InvoiceFetchUpcomingResponse -- client.invoices.issue(invoice_id) -> Invoice -- client.invoices.mark_paid(invoice_id, \*\*params) -> Invoice -- client.invoices.void(invoice_id) -> Invoice +- client.invoices.issue(invoice_id, \*\*params) -> Invoice +- client.invoices.issue_summary(invoice_id, \*\*params) -> InvoiceIssueSummaryResponse +- client.invoices.list_summary(\*\*params) -> SyncPage[InvoiceListSummaryResponse] +- client.invoices.mark_paid(invoice_id, \*\*params) -> Invoice +- client.invoices.pay(invoice_id, \*\*params) -> Invoice +- client.invoices.void(invoice_id) -> Invoice # Items @@ -245,7 +422,9 @@ from orb.types import Item Methods: - client.items.create(\*\*params) -> Item +- client.items.update(item_id, \*\*params) -> Item - client.items.list(\*\*params) -> SyncPage[Item] +- client.items.archive(item_id) -> Item - client.items.fetch(item_id) -> Item # Metrics @@ -253,14 +432,15 @@ Methods: Types: ```python -from orb.types import MetricCreateResponse, MetricListResponse, MetricFetchResponse +from orb.types import BillableMetric ``` Methods: -- client.metrics.create(\*\*params) -> MetricCreateResponse -- client.metrics.list(\*\*params) -> SyncPage[MetricListResponse] -- client.metrics.fetch(metric_id) -> MetricFetchResponse +- client.metrics.create(\*\*params) -> BillableMetric +- client.metrics.update(metric_id, \*\*params) -> BillableMetric +- client.metrics.list(\*\*params) -> SyncPage[BillableMetric] +- client.metrics.fetch(metric_id) -> BillableMetric # Plans @@ -284,25 +464,53 @@ Methods: - client.plans.external_plan_id.update(other_external_plan_id, \*\*params) -> Plan - client.plans.external_plan_id.fetch(external_plan_id) -> Plan +## Migrations + +Types: + +```python +from orb.types.plans import ( + MigrationRetrieveResponse, + MigrationListResponse, + MigrationCancelResponse, +) +``` + +Methods: + +- client.plans.migrations.retrieve(migration_id, \*, plan_id) -> MigrationRetrieveResponse +- client.plans.migrations.list(plan_id, \*\*params) -> SyncPage[MigrationListResponse] +- client.plans.migrations.cancel(migration_id, \*, plan_id) -> MigrationCancelResponse + # Prices Types: ```python -from orb.types import Price +from orb.types import ( + EvaluatePriceGroup, + PriceEvaluateResponse, + PriceEvaluateMultipleResponse, + PriceEvaluatePreviewEventsResponse, +) ``` Methods: -- client.prices.create(\*\*params) -> Price -- client.prices.list(\*\*params) -> SyncPage[Price] -- client.prices.fetch(price_id) -> Price +- client.prices.create(\*\*params) -> Price +- client.prices.update(price_id, \*\*params) -> Price +- client.prices.list(\*\*params) -> SyncPage[Price] +- client.prices.evaluate(price_id, \*\*params) -> PriceEvaluateResponse +- client.prices.evaluate_multiple(\*\*params) -> PriceEvaluateMultipleResponse +- client.prices.evaluate_preview_events(\*\*params) -> PriceEvaluatePreviewEventsResponse +- client.prices.fetch(price_id) -> Price ## ExternalPriceID Methods: -- client.prices.external_price_id.fetch(external_price_id) -> Price +- client.prices.external_price_id.update(external_price_id, \*\*params) -> Price +- client.prices.external_price_id.fetch(external_price_id) -> Price # Subscriptions @@ -310,6 +518,32 @@ Types: ```python from orb.types import ( + DiscountOverride, + NewSubscriptionBulkPrice, + NewSubscriptionBulkWithProrationPrice, + NewSubscriptionCumulativeGroupedBulkPrice, + NewSubscriptionGroupedAllocationPrice, + NewSubscriptionGroupedTieredPackagePrice, + NewSubscriptionGroupedTieredPrice, + NewSubscriptionGroupedWithMeteredMinimumPrice, + NewSubscriptionGroupedWithProratedMinimumPrice, + NewSubscriptionMatrixPrice, + NewSubscriptionMatrixWithAllocationPrice, + NewSubscriptionMatrixWithDisplayNamePrice, + NewSubscriptionMaxGroupTieredPackagePrice, + NewSubscriptionMinimumCompositePrice, + NewSubscriptionPackagePrice, + NewSubscriptionPackageWithAllocationPrice, + NewSubscriptionScalableMatrixWithTieredPricingPrice, + NewSubscriptionScalableMatrixWithUnitPricingPrice, + NewSubscriptionThresholdTotalAmountPrice, + NewSubscriptionTieredPackagePrice, + NewSubscriptionTieredPackageWithMinimumPrice, + NewSubscriptionTieredPrice, + NewSubscriptionTieredWithMinimumPrice, + NewSubscriptionUnitPrice, + NewSubscriptionUnitWithPercentPrice, + NewSubscriptionUnitWithProrationPrice, Subscription, SubscriptionUsage, Subscriptions, @@ -320,31 +554,161 @@ from orb.types import ( Methods: -- client.subscriptions.create(\*\*params) -> Subscription +- client.subscriptions.create(\*\*params) -> MutatedSubscription +- 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) -> MutatedSubscription - 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) -> MutatedSubscription +- client.subscriptions.redeem_coupon(subscription_id, \*\*params) -> MutatedSubscription +- client.subscriptions.schedule_plan_change(subscription_id, \*\*params) -> MutatedSubscription +- client.subscriptions.trigger_phase(subscription_id, \*\*params) -> MutatedSubscription +- client.subscriptions.unschedule_cancellation(subscription_id) -> MutatedSubscription +- client.subscriptions.unschedule_fixed_fee_quantity_updates(subscription_id, \*\*params) -> MutatedSubscription +- client.subscriptions.unschedule_pending_plan_changes(subscription_id) -> MutatedSubscription +- client.subscriptions.update_fixed_fee_quantity(subscription_id, \*\*params) -> MutatedSubscription +- client.subscriptions.update_trial(subscription_id, \*\*params) -> MutatedSubscription + +# Alerts -# Beta +Types: + +```python +from orb.types import Alert, Threshold +``` + +Methods: + +- client.alerts.retrieve(alert_id) -> Alert +- client.alerts.update(alert_configuration_id, \*\*params) -> Alert +- client.alerts.list(\*\*params) -> SyncPage[Alert] +- client.alerts.create_for_customer(customer_id, \*\*params) -> Alert +- client.alerts.create_for_external_customer(external_customer_id, \*\*params) -> Alert +- client.alerts.create_for_subscription(subscription_id, \*\*params) -> Alert +- client.alerts.disable(alert_configuration_id, \*\*params) -> Alert +- client.alerts.enable(alert_configuration_id, \*\*params) -> Alert -## Price +# DimensionalPriceGroups + +Types: + +```python +from orb.types import DimensionalPriceGroup, DimensionalPriceGroups +``` + +Methods: + +- client.dimensional_price_groups.create(\*\*params) -> DimensionalPriceGroup +- client.dimensional_price_groups.retrieve(dimensional_price_group_id) -> DimensionalPriceGroup +- client.dimensional_price_groups.update(dimensional_price_group_id, \*\*params) -> DimensionalPriceGroup +- client.dimensional_price_groups.list(\*\*params) -> SyncPage[DimensionalPriceGroup] + +## ExternalDimensionalPriceGroupID + +Methods: + +- client.dimensional_price_groups.external_dimensional_price_group_id.retrieve(external_dimensional_price_group_id) -> DimensionalPriceGroup +- client.dimensional_price_groups.external_dimensional_price_group_id.update(path_external_dimensional_price_group_id, \*\*params) -> DimensionalPriceGroup + +# SubscriptionChanges + +Types: + +```python +from orb.types import ( + MutatedSubscription, + SubscriptionChangeRetrieveResponse, + SubscriptionChangeListResponse, + SubscriptionChangeApplyResponse, + SubscriptionChangeCancelResponse, +) +``` + +Methods: + +- client.subscription_changes.retrieve(subscription_change_id) -> SubscriptionChangeRetrieveResponse +- client.subscription_changes.list(\*\*params) -> SyncPage[SubscriptionChangeListResponse] +- client.subscription_changes.apply(subscription_change_id, \*\*params) -> SubscriptionChangeApplyResponse +- client.subscription_changes.cancel(subscription_change_id) -> SubscriptionChangeCancelResponse + +# CreditBlocks + +Types: + +```python +from orb.types import CreditBlockRetrieveResponse, CreditBlockListInvoicesResponse +``` + +Methods: + +- client.credit_blocks.retrieve(block_id) -> CreditBlockRetrieveResponse +- client.credit_blocks.delete(block_id) -> None +- client.credit_blocks.list_invoices(block_id) -> CreditBlockListInvoicesResponse + +# LicenseTypes + +Types: + +```python +from orb.types import ( + LicenseTypeCreateResponse, + LicenseTypeRetrieveResponse, + LicenseTypeListResponse, +) +``` + +Methods: + +- client.license_types.create(\*\*params) -> LicenseTypeCreateResponse +- client.license_types.retrieve(license_type_id) -> LicenseTypeRetrieveResponse +- client.license_types.list(\*\*params) -> SyncPage[LicenseTypeListResponse] + +# Licenses + +Types: + +```python +from orb.types import ( + LicenseCreateResponse, + LicenseRetrieveResponse, + LicenseListResponse, + LicenseDeactivateResponse, + LicenseRetrieveByExternalIDResponse, +) +``` + +Methods: + +- client.licenses.create(\*\*params) -> LicenseCreateResponse +- client.licenses.retrieve(license_id) -> LicenseRetrieveResponse +- client.licenses.list(\*\*params) -> SyncPage[LicenseListResponse] +- client.licenses.deactivate(license_id, \*\*params) -> LicenseDeactivateResponse +- client.licenses.retrieve_by_external_id(external_license_id, \*\*params) -> LicenseRetrieveByExternalIDResponse + +## ExternalLicenses + +Types: + +```python +from orb.types.licenses import ExternalLicenseGetUsageResponse +``` + +Methods: + +- client.licenses.external_licenses.get_usage(external_license_id, \*\*params) -> ExternalLicenseGetUsageResponse + +## Usage Types: ```python -from orb.types.beta import EvaluatePriceGroup, PriceEvaluateResponse +from orb.types.licenses import UsageGetAllUsageResponse, UsageGetUsageResponse ``` Methods: -- client.beta.price.evaluate(price_id, \*\*params) -> PriceEvaluateResponse +- client.licenses.usage.get_all_usage(\*\*params) -> UsageGetAllUsageResponse +- client.licenses.usage.get_usage(license_id, \*\*params) -> UsageGetUsageResponse diff --git a/bin/check-env-state.py b/bin/check-env-state.py deleted file mode 100644 index e1b8b6cb..00000000 --- a/bin/check-env-state.py +++ /dev/null @@ -1,40 +0,0 @@ -"""Script that exits 1 if the current environment is not -in sync with the `requirements-dev.lock` file. -""" - -from pathlib import Path - -import importlib_metadata - - -def should_run_sync() -> bool: - dev_lock = Path(__file__).parent.parent.joinpath("requirements-dev.lock") - - for line in dev_lock.read_text().splitlines(): - if not line or line.startswith("#") or line.startswith("-e"): - continue - - dep, lock_version = line.split("==") - - try: - version = importlib_metadata.version(dep) - - if lock_version != version: - print(f"mismatch for {dep} current={version} lock={lock_version}") - return True - except Exception: - print(f"could not import {dep}") - return True - - return False - - -def main() -> None: - if should_run_sync(): - exit(1) - else: - exit(0) - - -if __name__ == "__main__": - main() diff --git a/bin/check-release-environment b/bin/check-release-environment index b0828071..b845b0f4 100644 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -3,7 +3,7 @@ errors=() if [ -z "${PYPI_TOKEN}" ]; then - errors+=("The ORB_PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") + errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") fi lenErrors=${#errors[@]} diff --git a/bin/check-test-server b/bin/check-test-server deleted file mode 100755 index a6fa3495..00000000 --- a/bin/check-test-server +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[0;33m' -NC='\033[0m' # No Color - -function prism_is_running() { - curl --silent "http://localhost:4010" >/dev/null 2>&1 -} - -function is_overriding_api_base_url() { - [ -n "$TEST_API_BASE_URL" ] -} - -if is_overriding_api_base_url ; then - # If someone is running the tests against the live API, we can trust they know - # what they're doing and exit early. - echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" - - exit 0 -elif prism_is_running ; then - echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" - echo - - exit 0 -else - echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" - echo -e "running against your OpenAPI spec." - echo - echo -e "${YELLOW}To fix:${NC}" - echo - echo -e "1. Install Prism (requires Node 16+):" - echo - echo -e " With npm:" - echo -e " \$ ${YELLOW}npm install -g @stoplight/prism-cli${NC}" - echo - echo -e " With yarn:" - echo -e " \$ ${YELLOW}yarn global add @stoplight/prism-cli${NC}" - echo - echo -e "2. Run the mock server" - echo - echo -e " To run the server, pass in the path of your OpenAPI" - echo -e " spec to the prism command:" - echo - echo -e " \$ ${YELLOW}prism mock path/to/your.openapi.yml${NC}" - echo - - exit 1 -fi diff --git a/bin/test b/bin/test deleted file mode 100755 index 60ede7a8..00000000 --- a/bin/test +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -bin/check-test-server && rye run pytest "$@" diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 283a4e20..00000000 --- a/mypy.ini +++ /dev/null @@ -1,47 +0,0 @@ -[mypy] -pretty = True -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)$ - -strict_equality = True -implicit_reexport = True -check_untyped_defs = True -no_implicit_optional = True - -warn_return_any = True -warn_unreachable = True -warn_unused_configs = True - -# Turn these options off as it could cause conflicts -# with the Pyright options. -warn_unused_ignores = False -warn_redundant_casts = False - -disallow_any_generics = True -disallow_untyped_defs = True -disallow_untyped_calls = True -disallow_subclassing_any = True -disallow_incomplete_defs = True -disallow_untyped_decorators = True -cache_fine_grained = True - -# By default, mypy reports an error if you assign a value to the result -# of a function call that doesn't return anything. We do this in our test -# cases: -# ``` -# result = ... -# assert result is None -# ``` -# Changing this codegen to make mypy happy would increase complexity -# and would not be worth it. -disable_error_code = func-returns-value - -# https://github.com/python/mypy/issues/12162 -[mypy.overrides] -module = "black.files.*" -ignore_errors = true -ignore_missing_imports = true diff --git a/pyproject.toml b/pyproject.toml index 24c97338..63c81e99 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,32 +1,32 @@ [project] name = "orb-billing" -version = "1.47.1" +version = "4.55.2" description = "The official Python library for the orb API" -readme = "README.md" +dynamic = ["readme"] license = "Apache-2.0" authors = [ { name = "Orb", email = "team@withorb.com" }, ] -dependencies = [ - "httpx>=0.23.0, <1", - "pydantic>=1.9.0, <3", - "typing-extensions>=4.7, <5", - "anyio>=3.5.0, <5", - "distro>=1.7.0, <2", - "sniffio", - "cached-property; python_version < '3.8'", +dependencies = [ + "httpx>=0.23.0, <1", + "pydantic>=1.9.0, <3", + "typing-extensions>=4.14, <5", + "anyio>=3.5.0, <5", + "distro>=1.7.0, <2", + "sniffio", ] -requires-python = ">= 3.7" + +requires-python = ">= 3.9" 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", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: MacOS", @@ -36,20 +36,19 @@ classifiers = [ "License :: OSI Approved :: Apache Software License" ] - - [project.urls] Homepage = "https://github.com/orbcorp/orb-python" Repository = "https://github.com/orbcorp/orb-python" - +[project.optional-dependencies] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.9"] [tool.rye] managed = true # version pins are in requirements-dev.lock dev-dependencies = [ - "pyright", - "mypy", + "pyright==1.1.399", + "mypy==1.17", "respx", "pytest", "pytest-asyncio", @@ -58,7 +57,8 @@ dev-dependencies = [ "nox", "dirty-equals>=0.6.0", "importlib-metadata>=6.7.0", - + "rich>=13.7.1", + "pytest-xdist>=3.6.1", ] [tool.rye.scripts] @@ -66,18 +66,21 @@ 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 bin/ruffen-docs.py README.md api.md" +"format:docs" = "bash -c 'python scripts/utils/ruffen-docs.py README.md $(find . -type f -name api.md)'" "format:ruff" = "ruff format" -"format:isort" = "isort ." "lint" = { chain = [ "check:ruff", "typecheck", + "check:importable", ]} -"check:ruff" = "ruff ." -"fix:ruff" = "ruff --fix ." +"check:ruff" = "ruff check ." +"fix:ruff" = "ruff check --fix ." + +"check:importable" = "python -c 'import orb'" typecheck = { chain = [ "typecheck:pyright", @@ -88,7 +91,7 @@ typecheck = { chain = [ "typecheck:mypy" = "mypy ." [build-system] -requires = ["hatchling"] +requires = ["hatchling==1.26.3", "hatch-fancy-pypi-readme"] build-backend = "hatchling.build" [tool.hatch.build] @@ -99,15 +102,38 @@ include = [ [tool.hatch.build.targets.wheel] packages = ["src/orb"] -[tool.black] -line-length = 120 -target-version = ["py37"] +[tool.hatch.build.targets.sdist] +# Basically everything except hidden files/directories (such as .github, .devcontainers, .python-version, etc) +include = [ + "/*.toml", + "/*.json", + "/*.lock", + "/*.md", + "/mypy.ini", + "/noxfile.py", + "bin/*", + "examples/*", + "src/*", + "tests/*", +] + +[tool.hatch.metadata.hooks.fancy-pypi-readme] +content-type = "text/markdown" + +[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] +path = "README.md" + +[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]] +# replace relative links with absolute links +pattern = '\[(.+?)\]\(((?!https?://)\S+?)\)' +replacement = '[\1](https://github.com/orbcorp/orb-python/tree/main/\g<2>)' [tool.pytest.ini_options] testpaths = ["tests"] -addopts = "--tb=short" +addopts = "--tb=short -n auto" xfail_strict = true asyncio_mode = "auto" +asyncio_default_fixture_loop_scope = "session" filterwarnings = [ "error" ] @@ -117,24 +143,82 @@ 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.9" exclude = [ "_dev", ".venv", ".nox", + ".git", ] reportImplicitOverride = true +reportOverlappingOverload = false reportImportCycles = false reportPrivateUsage = false +[tool.mypy] +pretty = true +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. +# +# 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 +check_untyped_defs = true +no_implicit_optional = true + +warn_return_any = true +warn_unreachable = true +warn_unused_configs = true + +# Turn these options off as it could cause conflicts +# with the Pyright options. +warn_unused_ignores = false +warn_redundant_casts = false + +disallow_any_generics = true +disallow_untyped_defs = true +disallow_untyped_calls = true +disallow_subclassing_any = true +disallow_incomplete_defs = true +disallow_untyped_decorators = true +cache_fine_grained = true + +# By default, mypy reports an error if you assign a value to the result +# of a function call that doesn't return anything. We do this in our test +# cases: +# ``` +# result = ... +# assert result is None +# ``` +# Changing this codegen to make mypy happy would increase complexity +# and would not be worth it. +disable_error_code = "func-returns-value,overload-cannot-match" + +# https://github.com/python/mypy/issues/12162 +[[tool.mypy.overrides]] +module = "black.files.*" +ignore_errors = true +ignore_missing_imports = true + [tool.ruff] line-length = 120 output-format = "grouped" -target-version = "py37" +target-version = "py38" + +[tool.ruff.format] +docstring-code-format = true + +[tool.ruff.lint] select = [ # isort "I", @@ -142,6 +226,8 @@ select = [ "B", # remove unused imports "F401", + # check for missing future annotations + "FA102", # bare except statements "E722", # unused arguments @@ -150,7 +236,9 @@ select = [ "T201", "T203", # misuse of typing.TYPE_CHECKING - "TCH004" + "TC004", + # import rules + "TID251", ] ignore = [ # mutable defaults @@ -161,10 +249,11 @@ unfixable = [ "T201", "T203", ] -ignore-init-module-imports = true -[tool.ruff.format] -docstring-code-format = true +extend-safe-fixes = ["FA102"] + +[tool.ruff.lint.flake8-tidy-imports.banned-api] +"functools.lru_cache".msg = "This function does not retain type information for the wrapped function's arguments; The `lru_cache` function from `_utils` should be used instead" [tool.ruff.lint.isort] length-sort = true @@ -173,7 +262,8 @@ combine-as-imports = true extra-standard-library = ["typing_extensions"] known-first-party = ["orb", "tests"] -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "bin/**.py" = ["T201", "T203"] +"scripts/**.py" = ["T201", "T203"] "tests/**.py" = ["T201", "T203"] "examples/**.py" = ["T201", "T203"] diff --git a/requirements-dev.lock b/requirements-dev.lock index 8cd3a6da..d92f7a5b 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -6,91 +6,144 @@ # features: [] # all-features: true # with-sources: false +# generate-hashes: false +# universal: false -e file:. -annotated-types==0.6.0 +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.13.3 + # via httpx-aiohttp + # via orb-billing +aiosignal==1.4.0 + # via aiohttp +annotated-types==0.7.0 # via pydantic -anyio==4.1.0 +anyio==4.12.1 # via httpx # via orb-billing -argcomplete==3.1.2 +argcomplete==3.6.3 # via nox -attrs==23.1.0 - # via pytest -certifi==2023.7.22 +async-timeout==5.0.1 + # via aiohttp +attrs==25.4.0 + # via aiohttp + # via nox +backports-asyncio-runner==1.2.0 + # via pytest-asyncio +certifi==2026.1.4 # via httpcore # via httpx -colorlog==6.7.0 +colorlog==6.10.1 + # via nox +dependency-groups==1.3.1 # via nox -dirty-equals==0.6.0 -distlib==0.3.7 +dirty-equals==0.11 +distlib==0.4.0 # via virtualenv -distro==1.8.0 +distro==1.9.0 # via orb-billing -exceptiongroup==1.1.3 +exceptiongroup==1.3.1 # via anyio -filelock==3.12.4 + # via pytest +execnet==2.1.2 + # via pytest-xdist +filelock==3.19.1 # via virtualenv -h11==0.14.0 +frozenlist==1.8.0 + # via aiohttp + # via aiosignal +h11==0.16.0 # via httpcore -httpcore==1.0.2 +httpcore==1.0.9 # via httpx -httpx==0.25.2 +httpx==0.28.1 + # via httpx-aiohttp # via orb-billing # via respx -idna==3.4 +httpx-aiohttp==0.1.12 + # via orb-billing +humanize==4.13.0 + # via nox +idna==3.11 # via anyio # via httpx -importlib-metadata==7.0.0 -iniconfig==2.0.0 + # via yarl +importlib-metadata==8.7.1 +iniconfig==2.1.0 # via pytest -mypy==1.7.1 -mypy-extensions==1.0.0 +markdown-it-py==3.0.0 + # via rich +mdurl==0.1.2 + # via markdown-it-py +multidict==6.7.0 + # via aiohttp + # via yarl +mypy==1.17.0 +mypy-extensions==1.1.0 # via mypy -nodeenv==1.8.0 +nodeenv==1.10.0 # via pyright -nox==2023.4.22 -packaging==23.2 +nox==2025.11.12 +packaging==25.0 + # via dependency-groups # via nox # via pytest -platformdirs==3.11.0 +pathspec==1.0.3 + # via mypy +platformdirs==4.4.0 # via virtualenv -pluggy==1.3.0 - # via pytest -py==1.11.0 +pluggy==1.6.0 # via pytest -pydantic==2.4.2 +propcache==0.4.1 + # via aiohttp + # via yarl +pydantic==2.12.5 # via orb-billing -pydantic-core==2.10.1 +pydantic-core==2.41.5 # via pydantic -pyright==1.1.353 -pytest==7.1.1 +pygments==2.19.2 + # via pytest + # via rich +pyright==1.1.399 +pytest==8.4.2 # via pytest-asyncio -pytest-asyncio==0.21.1 -python-dateutil==2.8.2 + # via pytest-xdist +pytest-asyncio==1.2.0 +pytest-xdist==3.8.0 +python-dateutil==2.9.0.post0 # via time-machine -pytz==2023.3.post1 - # via dirty-equals -respx==0.20.2 -ruff==0.1.9 -setuptools==68.2.2 - # via nodeenv -six==1.16.0 +respx==0.22.0 +rich==14.2.0 +ruff==0.14.13 +six==1.17.0 # via python-dateutil -sniffio==1.3.0 - # via anyio - # via httpx +sniffio==1.3.1 # via orb-billing -time-machine==2.9.0 -tomli==2.0.1 +time-machine==2.19.0 +tomli==2.4.0 + # via dependency-groups # via mypy + # via nox # via pytest -typing-extensions==4.8.0 +typing-extensions==4.15.0 + # via aiosignal + # via anyio + # via exceptiongroup + # via multidict # via mypy # via orb-billing # via pydantic # via pydantic-core -virtualenv==20.24.5 + # via pyright + # via pytest-asyncio + # via typing-inspection + # via virtualenv +typing-inspection==0.4.2 + # via pydantic +virtualenv==20.36.1 # via nox -zipp==3.17.0 +yarl==1.22.0 + # via aiohttp +zipp==3.23.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index c5aa659e..57cb0bcc 100644 --- a/requirements.lock +++ b/requirements.lock @@ -6,38 +6,71 @@ # features: [] # all-features: true # with-sources: false +# generate-hashes: false +# universal: false -e file:. -annotated-types==0.6.0 +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.13.3 + # via httpx-aiohttp + # via orb-billing +aiosignal==1.4.0 + # via aiohttp +annotated-types==0.7.0 # via pydantic -anyio==4.1.0 +anyio==4.12.1 # via httpx # via orb-billing -certifi==2023.7.22 +async-timeout==5.0.1 + # via aiohttp +attrs==25.4.0 + # via aiohttp +certifi==2026.1.4 # via httpcore # via httpx -distro==1.8.0 +distro==1.9.0 # via orb-billing -exceptiongroup==1.1.3 +exceptiongroup==1.3.1 # via anyio -h11==0.14.0 +frozenlist==1.8.0 + # via aiohttp + # via aiosignal +h11==0.16.0 # via httpcore -httpcore==1.0.2 +httpcore==1.0.9 # via httpx -httpx==0.25.2 +httpx==0.28.1 + # via httpx-aiohttp + # via orb-billing +httpx-aiohttp==0.1.12 # via orb-billing -idna==3.4 +idna==3.11 # via anyio # via httpx -pydantic==2.4.2 + # via yarl +multidict==6.7.0 + # via aiohttp + # via yarl +propcache==0.4.1 + # via aiohttp + # via yarl +pydantic==2.12.5 # via orb-billing -pydantic-core==2.10.1 +pydantic-core==2.41.5 # via pydantic -sniffio==1.3.0 - # via anyio - # via httpx +sniffio==1.3.1 # via orb-billing -typing-extensions==4.8.0 +typing-extensions==4.15.0 + # via aiosignal + # via anyio + # via exceptiongroup + # via multidict # via orb-billing # via pydantic # via pydantic-core + # via typing-inspection +typing-inspection==0.4.2 + # via pydantic +yarl==1.22.0 + # via aiohttp diff --git a/scripts/bootstrap b/scripts/bootstrap new file mode 100755 index 00000000..fe8451e4 --- /dev/null +++ b/scripts/bootstrap @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "${SKIP_BREW:-}" != "1" ] && [ -t 0 ]; then + brew bundle check >/dev/null 2>&1 || { + echo -n "==> Install Homebrew dependencies? (y/N): " + read -r response + case "$response" in + [yY][eE][sS]|[yY]) + brew bundle + ;; + *) + ;; + esac + echo + } +fi + +echo "==> Installing Python dependencies…" + +# experimental uv support makes installations significantly faster +rye config --set-bool behavior.use-uv=true + +rye sync --all-features diff --git a/scripts/format b/scripts/format new file mode 100755 index 00000000..667ec2d7 --- /dev/null +++ b/scripts/format @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +echo "==> Running formatters" +rye run format diff --git a/scripts/lint b/scripts/lint new file mode 100755 index 00000000..6d6cf944 --- /dev/null +++ b/scripts/lint @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +if [ "$1" = "--fix" ]; then + echo "==> Running lints with --fix" + rye run fix:ruff +else + echo "==> Running lints" + rye run lint +fi + +echo "==> Making sure it imports" +rye run python -c 'import orb' diff --git a/scripts/mock b/scripts/mock new file mode 100755 index 00000000..04d29019 --- /dev/null +++ b/scripts/mock @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +if [[ -n "$1" && "$1" != '--'* ]]; then + URL="$1" + shift +else + URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)" +fi + +# Check if the URL is empty +if [ -z "$URL" ]; then + echo "Error: No OpenAPI spec path/url provided or found in .stats.yml" + exit 1 +fi + +echo "==> Starting mock server with URL ${URL}" + +# Run steady mock on the given spec +if [ "$1" == "--daemon" ]; then + # Pre-install the package so the download doesn't eat into the startup timeout + npm exec --package=@stdy/cli@0.22.1 -- steady --version + + npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & + + # Wait for server to come online via health endpoint (max 30s) + echo -n "Waiting for server" + attempts=0 + while ! curl --silent --fail "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1; do + if ! kill -0 $! 2>/dev/null; then + echo + cat .stdy.log + exit 1 + fi + attempts=$((attempts + 1)) + if [ "$attempts" -ge 300 ]; then + echo + echo "Timed out waiting for Steady server to start" + cat .stdy.log + exit 1 + fi + echo -n "." + sleep 0.1 + done + + echo +else + npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" +fi diff --git a/scripts/test b/scripts/test new file mode 100755 index 00000000..7b05e44f --- /dev/null +++ b/scripts/test @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +NC='\033[0m' # No Color + +function steady_is_running() { + curl --silent "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1 +} + +kill_server_on_port() { + pids=$(lsof -t -i tcp:"$1" || echo "") + if [ "$pids" != "" ]; then + kill "$pids" + echo "Stopped $pids." + fi +} + +function is_overriding_api_base_url() { + [ -n "$TEST_API_BASE_URL" ] +} + +if ! is_overriding_api_base_url && ! steady_is_running ; then + # When we exit this script, make sure to kill the background mock server process + trap 'kill_server_on_port 4010' EXIT + + # Start the dev server + ./scripts/mock --daemon +fi + +if is_overriding_api_base_url ; then + echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" + echo +elif ! steady_is_running ; then + echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Steady server" + echo -e "running against your OpenAPI spec." + echo + echo -e "To run the server, pass in the path or url of your OpenAPI" + echo -e "spec to the steady command:" + echo + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.22.1 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=brackets --validator-form-array-format=brackets --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" + echo + + exit 1 +else + echo -e "${GREEN}✔ Mock steady server is running with your OpenAPI spec${NC}" + echo +fi + +export DEFER_PYDANTIC_BUILD=false + +echo "==> Running tests" +rye run pytest "$@" + +echo "==> Running Pydantic v1 tests" +rye run nox -s test-pydantic-v1 -- "$@" diff --git a/bin/ruffen-docs.py b/scripts/utils/ruffen-docs.py similarity index 97% rename from bin/ruffen-docs.py rename to scripts/utils/ruffen-docs.py index 37b3d94f..0cf2bd2f 100644 --- a/bin/ruffen-docs.py +++ b/scripts/utils/ruffen-docs.py @@ -47,7 +47,7 @@ def _md_match(match: Match[str]) -> str: with _collect_error(match): code = format_code_block(code) code = textwrap.indent(code, match["indent"]) - return f'{match["before"]}{code}{match["after"]}' + return f"{match['before']}{code}{match['after']}" def _pycon_match(match: Match[str]) -> str: code = "" @@ -97,7 +97,7 @@ def finish_fragment() -> None: def _md_pycon_match(match: Match[str]) -> str: code = _pycon_match(match) code = textwrap.indent(code, match["indent"]) - return f'{match["before"]}{code}{match["after"]}' + return f"{match['before']}{code}{match['after']}" src = MD_RE.sub(_md_match, src) src = MD_PYCON_RE.sub(_md_pycon_match, src) diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh new file mode 100755 index 00000000..f67398e8 --- /dev/null +++ b/scripts/utils/upload-artifact.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -exuo pipefail + +FILENAME=$(basename dist/*.whl) + +RESPONSE=$(curl -X POST "$URL?filename=$FILENAME" \ + -H "Authorization: Bearer $AUTH" \ + -H "Content-Type: application/json") + +SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url') + +if [[ "$SIGNED_URL" == "null" ]]; then + echo -e "\033[31mFailed to get signed URL.\033[0m" + exit 1 +fi + +UPLOAD_RESPONSE=$(curl -v -X PUT \ + -H "Content-Type: binary/octet-stream" \ + --data-binary "@dist/$FILENAME" "$SIGNED_URL" 2>&1) + +if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then + echo -e "\033[32mUploaded build to Stainless storage.\033[0m" + echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/orb-python/$SHA/$FILENAME'\033[0m" +else + echo -e "\033[31mFailed to upload artifact.\033[0m" + exit 1 +fi diff --git a/src/orb/__init__.py b/src/orb/__init__.py index e9a1c11d..9bd40a35 100644 --- a/src/orb/__init__.py +++ b/src/orb/__init__.py @@ -1,12 +1,15 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import typing as _t + from . import types -from ._types import NOT_GIVEN, NoneType, NotGiven, Transport, ProxiesTypes +from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes, omit, not_given from ._utils import file_from_path from ._client import Orb, Client, Stream, Timeout, AsyncOrb, Transport, AsyncClient, AsyncStream, RequestOptions from ._models import BaseModel from ._version import __title__, __version__ from ._response import APIResponse as APIResponse, AsyncAPIResponse as AsyncAPIResponse +from ._constants import DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES, DEFAULT_CONNECTION_LIMITS from ._exceptions import ( APIError, OrbError, @@ -35,6 +38,7 @@ DuplicateResourceCreation, APIResponseValidationError, ) +from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient from ._utils._logs import setup_logging as _setup_logging __all__ = [ @@ -46,6 +50,9 @@ "ProxiesTypes", "NotGiven", "NOT_GIVEN", + "not_given", + "Omit", + "omit", "OrbError", "APIError", "APIStatusError", @@ -82,8 +89,17 @@ "AsyncOrb", "file_from_path", "BaseModel", + "DEFAULT_TIMEOUT", + "DEFAULT_MAX_RETRIES", + "DEFAULT_CONNECTION_LIMITS", + "DefaultHttpxClient", + "DefaultAsyncHttpxClient", + "DefaultAioHttpClient", ] +if not _t.TYPE_CHECKING: + from ._utils._resources_proxy import resources as resources + _setup_logging() # Update the __module__ attribute for exported symbols so that diff --git a/src/orb/_base_client.py b/src/orb/_base_client.py index f431128e..86fbf71c 100644 --- a/src/orb/_base_client.py +++ b/src/orb/_base_client.py @@ -1,5 +1,6 @@ from __future__ import annotations +import sys import json import time import uuid @@ -29,21 +30,19 @@ cast, overload, ) -from functools import lru_cache from typing_extensions import Literal, override, get_origin import anyio import httpx import distro import pydantic -from httpx import URL, Limits +from httpx import URL from pydantic import PrivateAttr from . import _exceptions from ._qs import Querystring from ._files import to_httpx_files, async_to_httpx_files from ._types import ( - NOT_GIVEN, Body, Omit, Query, @@ -51,18 +50,19 @@ Timeout, NotGiven, ResponseT, - Transport, AnyMapping, PostParser, - ProxiesTypes, + BinaryTypes, RequestFiles, HttpxSendArgs, - AsyncTransport, RequestOptions, + AsyncBinaryTypes, + HttpxRequestFiles, ModelBuilderProtocol, + not_given, ) -from ._utils import is_dict, is_list, is_given, is_mapping -from ._compat import model_copy, model_dump +from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping +from ._compat import PYDANTIC_V1, model_copy, model_dump from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type from ._response import ( APIResponse, @@ -71,13 +71,13 @@ extract_response_type, ) from ._constants import ( - DEFAULT_LIMITS, DEFAULT_TIMEOUT, MAX_RETRY_DELAY, DEFAULT_MAX_RETRIES, INITIAL_RETRY_DELAY, RAW_RESPONSE_HEADER, OVERRIDE_CAST_TO_HEADER, + DEFAULT_CONNECTION_LIMITS, ) from ._streaming import Stream, SSEDecoder, AsyncStream, SSEBytesDecoder from ._exceptions import ( @@ -86,6 +86,7 @@ APIConnectionError, APIResponseValidationError, ) +from ._utils._json import openapi_dumps from ._legacy_response import LegacyAPIResponse log: logging.Logger = logging.getLogger(__name__) @@ -102,7 +103,11 @@ _AsyncStreamT = TypeVar("_AsyncStreamT", bound=AsyncStream[Any]) if TYPE_CHECKING: - from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT + from httpx._config import ( + DEFAULT_TIMEOUT_CONFIG, # pyright: ignore[reportPrivateImportUsage] + ) + + HTTPX_DEFAULT_TIMEOUT = DEFAULT_TIMEOUT_CONFIG else: try: from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT @@ -119,32 +124,48 @@ class PageInfo: url: URL | NotGiven params: Query | NotGiven + json: Body | NotGiven @overload def __init__( self, *, url: URL, - ) -> None: - ... + ) -> None: ... @overload def __init__( self, *, params: Query, - ) -> None: - ... + ) -> None: ... + @overload def __init__( self, *, - url: URL | NotGiven = NOT_GIVEN, - params: Query | NotGiven = NOT_GIVEN, + json: Body, + ) -> None: ... + + def __init__( + self, + *, + url: URL | NotGiven = not_given, + json: Body | NotGiven = not_given, + params: Query | NotGiven = not_given, ) -> None: self.url = url + self.json = json self.params = params + @override + def __repr__(self) -> str: + if self.url: + return f"{self.__class__.__name__}(url={self.url})" + if self.json: + return f"{self.__class__.__name__}(json={self.json})" + return f"{self.__class__.__name__}(params={self.params})" + class BasePage(GenericModel, Generic[_T]): """ @@ -167,8 +188,7 @@ def has_next_page(self) -> bool: return False return self.next_page_info() is not None - def next_page_info(self) -> Optional[PageInfo]: - ... + def next_page_info(self) -> Optional[PageInfo]: ... def _get_page_items(self) -> Iterable[_T]: # type: ignore[empty-body] ... @@ -192,6 +212,19 @@ def _info_to_options(self, info: PageInfo) -> FinalRequestOptions: options.url = str(url) return options + if not isinstance(info.json, NotGiven): + if not is_mapping(info.json): + raise TypeError("Pagination is only supported with mappings") + + if not options.json_data: + options.json_data = {**info.json} + else: + if not is_mapping(options.json_data): + raise TypeError("Pagination is only supported with mappings") + + options.json_data = {**options.json_data, **info.json} + return options + raise ValueError("Unexpected PageInfo state") @@ -204,6 +237,9 @@ def _set_private_attributes( model: Type[_T], options: FinalRequestOptions, ) -> None: + if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: + self.__pydantic_private__ = {} + self._model = model self._client = client self._options = options @@ -289,6 +325,9 @@ def _set_private_attributes( client: AsyncAPIClient, options: FinalRequestOptions, ) -> None: + if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: + self.__pydantic_private__ = {} + self._model = model self._client = client self._options = options @@ -328,9 +367,6 @@ class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]): _base_url: URL max_retries: int timeout: Union[float, Timeout, None] - _limits: httpx.Limits - _proxies: ProxiesTypes | None - _transport: Transport | AsyncTransport | None _strict_response_validation: bool _idempotency_header: str | None _default_stream_cls: type[_DefaultStreamT] | None = None @@ -343,9 +379,6 @@ def __init__( _strict_response_validation: bool, max_retries: int = DEFAULT_MAX_RETRIES, timeout: float | Timeout | None = DEFAULT_TIMEOUT, - limits: httpx.Limits, - transport: Transport | AsyncTransport | None, - proxies: ProxiesTypes | None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, ) -> None: @@ -353,13 +386,16 @@ def __init__( self._base_url = self._enforce_trailing_slash(URL(base_url)) self.max_retries = max_retries self.timeout = timeout - self._limits = limits - self._proxies = proxies - self._transport = transport self._custom_headers = custom_headers or {} self._custom_query = custom_query or {} self._strict_response_validation = _strict_response_validation self._idempotency_header = None + self._platform: Platform | None = None + + if max_retries is None: # pyright: ignore[reportUnnecessaryComparison] + raise TypeError( + "max_retries cannot be None. If you want to disable retries, pass `0`; if you want unlimited retries, pass `math.inf` or a very high number; if you want the default behavior, pass `orb.DEFAULT_MAX_RETRIES`" + ) def _enforce_trailing_slash(self, url: URL) -> URL: if url.raw_path.endswith(b"/"): @@ -397,14 +433,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) @@ -413,8 +442,20 @@ def _build_headers(self, options: FinalRequestOptions) -> httpx.Headers: headers = httpx.Headers(headers_dict) idempotency_header = self._idempotency_header - if idempotency_header and options.method.lower() != "get" and idempotency_header not in headers: - headers[idempotency_header] = options.idempotency_key or self._idempotency_key() + if idempotency_header and options.idempotency_key and idempotency_header not in headers: + headers[idempotency_header] = options.idempotency_key + + # Don't set these headers if they were already set or removed by the caller. We check + # `custom_headers`, which can contain `Omit()`, instead of `headers` to account for the removal case. + lower_custom_headers = [header.lower() for header in custom_headers] + if "x-stainless-retry-count" not in lower_custom_headers: + headers["x-stainless-retry-count"] = str(retries_taken) + if "x-stainless-read-timeout" not in lower_custom_headers: + timeout = self.timeout if isinstance(options.timeout, NotGiven) else options.timeout + if isinstance(timeout, Timeout): + timeout = timeout.read + if timeout is not None: + headers["x-stainless-read-timeout"] = str(timeout) return headers @@ -437,10 +478,23 @@ 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)) - + log.debug( + "Request options: %s", + model_dump( + options, + exclude_unset=True, + # Pydantic v1 can't dump every type we support in content, so we exclude it for now. + exclude={ + "content", + } + if PYDANTIC_V1 + else {}, + ), + ) kwargs: dict[str, Any] = {} json_data = options.json_data @@ -452,9 +506,10 @@ def _build_request( else: raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`") - headers = self._build_headers(options) - params = _merge_mappings(self._custom_query, options.params) + 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 # If the given Content-Type header is multipart/form-data then it # has to be removed so that httpx can generate the header with @@ -468,7 +523,7 @@ def _build_request( headers.pop("Content-Type") # As we are now sending multipart/form-data instead of application/json - # we need to tell httpx to use it, https://www.python-httpx.org/advanced/#multipart-file-encoding + # we need to tell httpx to use it, https://www.python-httpx.org/advanced/clients/#multipart-file-encoding if json_data: if not is_dict(json_data): raise TypeError( @@ -476,19 +531,55 @@ def _build_request( ) kwargs["data"] = self._serialize_multipartform(json_data) + # httpx determines whether or not to send a "multipart/form-data" + # request based on the truthiness of the "files" argument. + # This gets around that issue by generating a dict value that + # evaluates to true. + # + # https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186 + if not files: + files = cast(HttpxRequestFiles, ForceMultipartDict()) + + prepared_url = self._prepare_url(options.url) + # preserve hard-coded query params from the url + if params and prepared_url.query: + params = {**dict(prepared_url.params.items()), **params} + prepared_url = prepared_url.copy_with(raw_path=prepared_url.raw_path.split(b"?", 1)[0]) + if "_" in prepared_url.host: + # work around https://github.com/encode/httpx/discussions/2880 + kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} + + is_body_allowed = options.method.lower() != "get" + + if is_body_allowed: + if options.content is not None and json_data is not None: + raise TypeError("Passing both `content` and `json_data` is not supported") + if options.content is not None and files is not None: + raise TypeError("Passing both `content` and `files` is not supported") + if options.content is not None: + kwargs["content"] = options.content + elif isinstance(json_data, bytes): + kwargs["content"] = json_data + elif not files: + # Don't set content when JSON is sent as multipart/form-data, + # since httpx's content param overrides other body arguments + kwargs["content"] = openapi_dumps(json_data) if is_given(json_data) and json_data is not None else None + kwargs["files"] = files + else: + headers.pop("Content-Type", None) + kwargs.pop("data", None) + # 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. # https://github.com/microsoft/pyright/issues/3526#event-6715453066 params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None, - json=json_data, - files=options.files, **kwargs, ) @@ -532,7 +623,7 @@ def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalReques # we internally support defining a temporary header to override the # default `cast_to` type for use with `.with_raw_response` and `.with_streaming_response` # see _response.py for implementation details - override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, NOT_GIVEN) + override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, not_given) if is_given(override_cast_to): options.headers = headers return cast(Type[ResponseT], override_cast_to) @@ -589,6 +680,12 @@ def default_headers(self) -> dict[str, str | Omit]: **self._custom_headers, } + @property + def default_query(self) -> dict[str, object]: + return { + **self._custom_query, + } + def _validate_headers( self, headers: Headers, # noqa: ARG002 @@ -613,7 +710,10 @@ def base_url(self, url: URL | str) -> None: self._base_url = self._enforce_trailing_slash(url if isinstance(url, URL) else URL(url)) def platform_headers(self) -> Dict[str, str]: - return platform_headers(self._version) + # the actual implementation is in a separate `lru_cache` decorated + # function because adding `lru_cache` to methods will leak memory + # https://github.com/python/cpython/issues/88476 + return platform_headers(self._version, platform=self._platform) def _parse_retry_after_header(self, response_headers: Optional[httpx.Headers] = None) -> float | None: """Returns a float of the number of seconds (not milliseconds) to wait after retrying, or None if unspecified. @@ -662,7 +762,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) @@ -711,8 +812,31 @@ def _idempotency_key(self) -> str: return f"stainless-python-retry-{uuid.uuid4()}" -class SyncHttpxClientWrapper(httpx.Client): +class _DefaultHttpxClient(httpx.Client): + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + super().__init__(**kwargs) + + +if TYPE_CHECKING: + DefaultHttpxClient = httpx.Client + """An alias to `httpx.Client` that provides the same defaults that this SDK + uses internally. + + This is useful because overriding the `http_client` with your own instance of + `httpx.Client` will result in httpx's defaults being used, not ours. + """ +else: + DefaultHttpxClient = _DefaultHttpxClient + + +class SyncHttpxClientWrapper(DefaultHttpxClient): def __del__(self) -> None: + if self.is_closed: + return + try: self.close() except Exception: @@ -729,44 +853,12 @@ def __init__( version: str, base_url: str | URL, max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, - transport: Transport | None = None, - proxies: ProxiesTypes | None = None, - limits: Limits | None = None, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.Client | None = None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, _strict_response_validation: bool, ) -> None: - if limits is not None: - warnings.warn( - "The `connection_pool_limits` argument is deprecated. The `http_client` argument should be passed instead", - category=DeprecationWarning, - stacklevel=3, - ) - if http_client is not None: - raise ValueError("The `http_client` argument is mutually exclusive with `connection_pool_limits`") - else: - limits = DEFAULT_LIMITS - - if transport is not None: - warnings.warn( - "The `transport` argument is deprecated. The `http_client` argument should be passed instead", - category=DeprecationWarning, - stacklevel=3, - ) - if http_client is not None: - raise ValueError("The `http_client` argument is mutually exclusive with `transport`") - - if proxies is not None: - warnings.warn( - "The `proxies` argument is deprecated. The `http_client` argument should be passed instead", - category=DeprecationWarning, - stacklevel=3, - ) - if http_client is not None: - raise ValueError("The `http_client` argument is mutually exclusive with `proxies`") - if not is_given(timeout): # if the user passed in a custom http client with a non-default # timeout set then we use that timeout. @@ -787,12 +879,9 @@ def __init__( super().__init__( version=version, - limits=limits, # cast to a valid type because mypy doesn't understand our type narrowing timeout=cast(Timeout, timeout), - proxies=proxies, base_url=base_url, - transport=transport, max_retries=max_retries, custom_query=custom_query, custom_headers=custom_headers, @@ -802,10 +891,6 @@ 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, ) def is_closed(self) -> bool: @@ -835,9 +920,9 @@ def __exit__( def _prepare_options( self, options: FinalRequestOptions, # noqa: ARG002 - ) -> None: + ) -> FinalRequestOptions: """Hook for mutating the given options""" - return None + return options def _prepare_request( self, @@ -855,177 +940,163 @@ def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, - remaining_retries: Optional[int] = None, *, stream: Literal[True], stream_cls: Type[_StreamT], - ) -> _StreamT: - ... + ) -> _StreamT: ... @overload def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, - remaining_retries: Optional[int] = None, *, stream: Literal[False] = False, - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, - remaining_retries: Optional[int] = None, *, stream: bool = False, stream_cls: Type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: - ... + ) -> ResponseT | _StreamT: ... def request( self, cast_to: Type[ResponseT], options: FinalRequestOptions, - remaining_retries: Optional[int] = None, *, stream: bool = False, stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: - return self._request( - cast_to=cast_to, - options=options, - stream=stream, - stream_cls=stream_cls, - remaining_retries=remaining_retries, - ) - - def _request( - self, - *, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - remaining_retries: int | None, - stream: bool, - stream_cls: type[_StreamT] | None, ) -> ResponseT | _StreamT: cast_to = self._maybe_override_cast_to(cast_to, options) - self._prepare_options(options) - retries = self._remaining_retries(remaining_retries, options) - request = self._build_request(options) - self._prepare_request(request) + # create a copy of the options we were given so that if the + # options are mutated later & we then retry, the retries are + # given the original options + input_options = model_copy(options) + if input_options.idempotency_key is None and input_options.method.lower() != "get": + # ensure the idempotency key is reused between requests + input_options.idempotency_key = self._idempotency_key() - kwargs: HttpxSendArgs = {} - if self.custom_auth is not None: - kwargs["auth"] = self.custom_auth + response: httpx.Response | None = None + max_retries = input_options.get_max_retries(self.max_retries) - try: - response = self._client.send( - request, - stream=stream or self._should_stream_response_body(request=request), - **kwargs, - ) - except httpx.TimeoutException as err: - log.debug("Encountered httpx.TimeoutException", exc_info=True) + retries_taken = 0 + for retries_taken in range(max_retries + 1): + options = model_copy(input_options) + options = self._prepare_options(options) - if retries > 0: - return self._retry_request( - options, - cast_to, - retries, - stream=stream, - stream_cls=stream_cls, - response_headers=None, - ) + remaining_retries = max_retries - retries_taken + request = self._build_request(options, retries_taken=retries_taken) + self._prepare_request(request) - log.debug("Raising timeout error") - raise APITimeoutError(request=request) from err - except Exception as err: - log.debug("Encountered Exception", exc_info=True) + kwargs: HttpxSendArgs = {} + if self.custom_auth is not None: + kwargs["auth"] = self.custom_auth - if retries > 0: - return self._retry_request( - options, - cast_to, - retries, - stream=stream, - stream_cls=stream_cls, - response_headers=None, - ) + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects - log.debug("Raising connection error") - raise APIConnectionError(request=request) from err + log.debug("Sending HTTP Request: %s %s", request.method, request.url) - log.debug( - 'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase - ) + response = None + try: + response = self._client.send( + request, + stream=stream or self._should_stream_response_body(request=request), + **kwargs, + ) + except httpx.TimeoutException as err: + log.debug("Encountered httpx.TimeoutException", exc_info=True) + + if remaining_retries > 0: + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising timeout error") + raise APITimeoutError(request=request) from err + except Exception as err: + log.debug("Encountered Exception", exc_info=True) + + if remaining_retries > 0: + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising connection error") + raise APIConnectionError(request=request) from err + + log.debug( + 'HTTP Response: %s %s "%i %s" %s', + request.method, + request.url, + response.status_code, + response.reason_phrase, + response.headers, + ) - try: - response.raise_for_status() - except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code - log.debug("Encountered httpx.HTTPStatusError", exc_info=True) + try: + response.raise_for_status() + except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code + log.debug("Encountered httpx.HTTPStatusError", exc_info=True) + + if remaining_retries > 0 and self._should_retry(err.response): + err.response.close() + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=response, + ) + continue - if retries > 0 and self._should_retry(err.response): - err.response.close() - return self._retry_request( - options, - cast_to, - retries, - err.response.headers, - stream=stream, - stream_cls=stream_cls, - ) + # If the response is streamed then we need to explicitly read the response + # to completion before attempting to access the response text. + if not err.response.is_closed: + err.response.read() - # If the response is streamed then we need to explicitly read the response - # to completion before attempting to access the response text. - if not err.response.is_closed: - err.response.read() + log.debug("Re-raising status error") + raise self._make_status_error_from_response(err.response) from None - log.debug("Re-raising status error") - raise self._make_status_error_from_response(err.response) from None + break + assert response is not None, "could not resolve response (should never happen)" return self._process_response( cast_to=cast_to, options=options, response=response, stream=stream, stream_cls=stream_cls, + retries_taken=retries_taken, ) - def _retry_request( - self, - options: FinalRequestOptions, - cast_to: Type[ResponseT], - remaining_retries: int, - response_headers: httpx.Headers | None, - *, - stream: bool, - stream_cls: type[_StreamT] | None, - ) -> ResponseT | _StreamT: - remaining = remaining_retries - 1 - if remaining == 1: + def _sleep_for_retry( + self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None + ) -> None: + remaining_retries = 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 if response else None) 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 - # different thread if necessary. time.sleep(timeout) - return self._request( - options=options, - cast_to=cast_to, - remaining_retries=remaining, - stream=stream, - stream_cls=stream_cls, - ) - def _process_response( self, *, @@ -1034,6 +1105,7 @@ def _process_response( response: httpx.Response, stream: bool, stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, + retries_taken: int = 0, ) -> ResponseT: if response.request.headers.get(RAW_RESPONSE_HEADER) == "true": return cast( @@ -1045,12 +1117,20 @@ def _process_response( stream=stream, stream_cls=stream_cls, options=options, + retries_taken=retries_taken, ), ) origin = get_origin(cast_to) or cast_to - if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse): + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): if not issubclass(origin, APIResponse): raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}") @@ -1064,6 +1144,7 @@ def _process_response( stream=stream, stream_cls=stream_cls, options=options, + retries_taken=retries_taken, ), ) @@ -1077,6 +1158,7 @@ def _process_response( stream=stream, stream_cls=stream_cls, options=options, + retries_taken=retries_taken, ) if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): return cast(ResponseT, api_response) @@ -1109,8 +1191,7 @@ def get( cast_to: Type[ResponseT], options: RequestOptions = {}, stream: Literal[False] = False, - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload def get( @@ -1121,8 +1202,7 @@ def get( options: RequestOptions = {}, stream: Literal[True], stream_cls: type[_StreamT], - ) -> _StreamT: - ... + ) -> _StreamT: ... @overload def get( @@ -1133,8 +1213,7 @@ def get( options: RequestOptions = {}, stream: bool, stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: - ... + ) -> ResponseT | _StreamT: ... def get( self, @@ -1157,11 +1236,11 @@ def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, files: RequestFiles | None = None, stream: Literal[False] = False, - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload def post( @@ -1170,12 +1249,12 @@ def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, files: RequestFiles | None = None, stream: Literal[True], stream_cls: type[_StreamT], - ) -> _StreamT: - ... + ) -> _StreamT: ... @overload def post( @@ -1184,12 +1263,12 @@ def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, files: RequestFiles | None = None, stream: bool, stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: - ... + ) -> ResponseT | _StreamT: ... def post( self, @@ -1197,13 +1276,25 @@ def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, files: RequestFiles | None = None, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) opts = FinalRequestOptions.construct( - method="post", url=path, json_data=body, files=to_httpx_files(files), **options + method="post", url=path, json_data=body, content=content, files=to_httpx_files(files), **options ) return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) @@ -1213,9 +1304,24 @@ def patch( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, + files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options) + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="patch", url=path, json_data=body, content=content, files=to_httpx_files(files), **options + ) return self.request(cast_to, opts) def put( @@ -1224,11 +1330,23 @@ def put( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) opts = FinalRequestOptions.construct( - method="put", url=path, json_data=body, files=to_httpx_files(files), **options + method="put", url=path, json_data=body, content=content, files=to_httpx_files(files), **options ) return self.request(cast_to, opts) @@ -1238,9 +1356,19 @@ def delete( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options) + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options) return self.request(cast_to, opts) def get_api_list( @@ -1257,8 +1385,53 @@ def get_api_list( return self._request_api_list(model, page, opts) -class AsyncHttpxClientWrapper(httpx.AsyncClient): +class _DefaultAsyncHttpxClient(httpx.AsyncClient): + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + super().__init__(**kwargs) + + +try: + import httpx_aiohttp +except ImportError: + + class _DefaultAioHttpClient(httpx.AsyncClient): + def __init__(self, **_kwargs: Any) -> None: + raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra") +else: + + class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + + super().__init__(**kwargs) + + +if TYPE_CHECKING: + DefaultAsyncHttpxClient = httpx.AsyncClient + """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK + uses internally. + + This is useful because overriding the `http_client` with your own instance of + `httpx.AsyncClient` will result in httpx's defaults being used, not ours. + """ + + DefaultAioHttpClient = httpx.AsyncClient + """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`.""" +else: + DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient + DefaultAioHttpClient = _DefaultAioHttpClient + + +class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): def __del__(self) -> None: + if self.is_closed: + return + try: # TODO(someday): support non asyncio runtimes here asyncio.get_running_loop().create_task(self.aclose()) @@ -1277,43 +1450,11 @@ def __init__( base_url: str | URL, _strict_response_validation: bool, max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, - transport: AsyncTransport | None = None, - proxies: ProxiesTypes | None = None, - limits: Limits | None = None, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.AsyncClient | None = None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, ) -> None: - if limits is not None: - warnings.warn( - "The `connection_pool_limits` argument is deprecated. The `http_client` argument should be passed instead", - category=DeprecationWarning, - stacklevel=3, - ) - if http_client is not None: - raise ValueError("The `http_client` argument is mutually exclusive with `connection_pool_limits`") - else: - limits = DEFAULT_LIMITS - - if transport is not None: - warnings.warn( - "The `transport` argument is deprecated. The `http_client` argument should be passed instead", - category=DeprecationWarning, - stacklevel=3, - ) - if http_client is not None: - raise ValueError("The `http_client` argument is mutually exclusive with `transport`") - - if proxies is not None: - warnings.warn( - "The `proxies` argument is deprecated. The `http_client` argument should be passed instead", - category=DeprecationWarning, - stacklevel=3, - ) - if http_client is not None: - raise ValueError("The `http_client` argument is mutually exclusive with `proxies`") - if not is_given(timeout): # if the user passed in a custom http client with a non-default # timeout set then we use that timeout. @@ -1335,11 +1476,8 @@ def __init__( super().__init__( version=version, base_url=base_url, - limits=limits, # cast to a valid type because mypy doesn't understand our type narrowing timeout=cast(Timeout, timeout), - proxies=proxies, - transport=transport, max_retries=max_retries, custom_query=custom_query, custom_headers=custom_headers, @@ -1349,10 +1487,6 @@ 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, ) def is_closed(self) -> bool: @@ -1379,9 +1513,9 @@ async def __aexit__( async def _prepare_options( self, options: FinalRequestOptions, # noqa: ARG002 - ) -> None: + ) -> FinalRequestOptions: """Hook for mutating the given options""" - return None + return options async def _prepare_request( self, @@ -1401,9 +1535,7 @@ async def request( options: FinalRequestOptions, *, stream: Literal[False] = False, - remaining_retries: Optional[int] = None, - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload async def request( @@ -1413,9 +1545,7 @@ async def request( *, stream: Literal[True], stream_cls: type[_AsyncStreamT], - remaining_retries: Optional[int] = None, - ) -> _AsyncStreamT: - ... + ) -> _AsyncStreamT: ... @overload async def request( @@ -1425,9 +1555,7 @@ async def request( *, stream: bool, stream_cls: type[_AsyncStreamT] | None = None, - remaining_retries: Optional[int] = None, - ) -> ResponseT | _AsyncStreamT: - ... + ) -> ResponseT | _AsyncStreamT: ... async def request( self, @@ -1436,138 +1564,137 @@ async def request( *, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, - remaining_retries: Optional[int] = None, ) -> ResponseT | _AsyncStreamT: - return await self._request( - cast_to=cast_to, - options=options, - stream=stream, - stream_cls=stream_cls, - remaining_retries=remaining_retries, - ) + if self._platform is None: + # `get_platform` can make blocking IO calls so we + # execute it earlier while we are in an async context + self._platform = await asyncify(get_platform)() - async def _request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: bool, - stream_cls: type[_AsyncStreamT] | None, - remaining_retries: int | None, - ) -> ResponseT | _AsyncStreamT: cast_to = self._maybe_override_cast_to(cast_to, options) - await self._prepare_options(options) - retries = self._remaining_retries(remaining_retries, options) - request = self._build_request(options) - await self._prepare_request(request) + # create a copy of the options we were given so that if the + # options are mutated later & we then retry, the retries are + # given the original options + input_options = model_copy(options) + if input_options.idempotency_key is None and input_options.method.lower() != "get": + # ensure the idempotency key is reused between requests + input_options.idempotency_key = self._idempotency_key() - kwargs: HttpxSendArgs = {} - if self.custom_auth is not None: - kwargs["auth"] = self.custom_auth + response: httpx.Response | None = None + max_retries = input_options.get_max_retries(self.max_retries) - try: - response = await self._client.send( - request, - stream=stream or self._should_stream_response_body(request=request), - **kwargs, - ) - except httpx.TimeoutException as err: - log.debug("Encountered httpx.TimeoutException", exc_info=True) + retries_taken = 0 + for retries_taken in range(max_retries + 1): + options = model_copy(input_options) + options = await self._prepare_options(options) - if retries > 0: - return await self._retry_request( - options, - cast_to, - retries, - stream=stream, - stream_cls=stream_cls, - response_headers=None, - ) + remaining_retries = max_retries - retries_taken + request = self._build_request(options, retries_taken=retries_taken) + await self._prepare_request(request) - log.debug("Raising timeout error") - raise APITimeoutError(request=request) from err - except Exception as err: - log.debug("Encountered Exception", exc_info=True) + kwargs: HttpxSendArgs = {} + if self.custom_auth is not None: + kwargs["auth"] = self.custom_auth - if retries > 0: - return await self._retry_request( - options, - cast_to, - retries, - stream=stream, - stream_cls=stream_cls, - response_headers=None, - ) + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects - log.debug("Raising connection error") - raise APIConnectionError(request=request) from err + log.debug("Sending HTTP Request: %s %s", request.method, request.url) - log.debug( - 'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase - ) + response = None + try: + response = await self._client.send( + request, + stream=stream or self._should_stream_response_body(request=request), + **kwargs, + ) + except httpx.TimeoutException as err: + log.debug("Encountered httpx.TimeoutException", exc_info=True) + + if remaining_retries > 0: + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising timeout error") + raise APITimeoutError(request=request) from err + except Exception as err: + log.debug("Encountered Exception", exc_info=True) + + if remaining_retries > 0: + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising connection error") + raise APIConnectionError(request=request) from err + + log.debug( + 'HTTP Response: %s %s "%i %s" %s', + request.method, + request.url, + response.status_code, + response.reason_phrase, + response.headers, + ) - try: - response.raise_for_status() - except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code - log.debug("Encountered httpx.HTTPStatusError", exc_info=True) + try: + response.raise_for_status() + except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code + log.debug("Encountered httpx.HTTPStatusError", exc_info=True) + + if remaining_retries > 0 and self._should_retry(err.response): + await err.response.aclose() + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=response, + ) + continue - if retries > 0 and self._should_retry(err.response): - await err.response.aclose() - return await self._retry_request( - options, - cast_to, - retries, - err.response.headers, - stream=stream, - stream_cls=stream_cls, - ) + # If the response is streamed then we need to explicitly read the response + # to completion before attempting to access the response text. + if not err.response.is_closed: + await err.response.aread() - # If the response is streamed then we need to explicitly read the response - # to completion before attempting to access the response text. - if not err.response.is_closed: - await err.response.aread() + log.debug("Re-raising status error") + raise self._make_status_error_from_response(err.response) from None - log.debug("Re-raising status error") - raise self._make_status_error_from_response(err.response) from None + break + assert response is not None, "could not resolve response (should never happen)" return await self._process_response( cast_to=cast_to, options=options, response=response, stream=stream, stream_cls=stream_cls, + retries_taken=retries_taken, ) - async def _retry_request( - self, - options: FinalRequestOptions, - cast_to: Type[ResponseT], - remaining_retries: int, - response_headers: httpx.Headers | None, - *, - stream: bool, - stream_cls: type[_AsyncStreamT] | None, - ) -> ResponseT | _AsyncStreamT: - remaining = remaining_retries - 1 - if remaining == 1: + async def _sleep_for_retry( + self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None + ) -> None: + remaining_retries = 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 if response else None) log.info("Retrying request to %s in %f seconds", options.url, timeout) await anyio.sleep(timeout) - return await self._request( - options=options, - cast_to=cast_to, - remaining_retries=remaining, - stream=stream, - stream_cls=stream_cls, - ) - async def _process_response( self, *, @@ -1576,6 +1703,7 @@ async def _process_response( response: httpx.Response, stream: bool, stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, + retries_taken: int = 0, ) -> ResponseT: if response.request.headers.get(RAW_RESPONSE_HEADER) == "true": return cast( @@ -1587,12 +1715,20 @@ async def _process_response( stream=stream, stream_cls=stream_cls, options=options, + retries_taken=retries_taken, ), ) origin = get_origin(cast_to) or cast_to - if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse): + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): if not issubclass(origin, AsyncAPIResponse): raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}") @@ -1606,6 +1742,7 @@ async def _process_response( stream=stream, stream_cls=stream_cls, options=options, + retries_taken=retries_taken, ), ) @@ -1619,6 +1756,7 @@ async def _process_response( stream=stream, stream_cls=stream_cls, options=options, + retries_taken=retries_taken, ) if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): return cast(ResponseT, api_response) @@ -1641,8 +1779,7 @@ async def get( cast_to: Type[ResponseT], options: RequestOptions = {}, stream: Literal[False] = False, - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload async def get( @@ -1653,8 +1790,7 @@ async def get( options: RequestOptions = {}, stream: Literal[True], stream_cls: type[_AsyncStreamT], - ) -> _AsyncStreamT: - ... + ) -> _AsyncStreamT: ... @overload async def get( @@ -1665,8 +1801,7 @@ async def get( options: RequestOptions = {}, stream: bool, stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: - ... + ) -> ResponseT | _AsyncStreamT: ... async def get( self, @@ -1687,11 +1822,11 @@ async def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, stream: Literal[False] = False, - ) -> ResponseT: - ... + ) -> ResponseT: ... @overload async def post( @@ -1700,12 +1835,12 @@ async def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, stream: Literal[True], stream_cls: type[_AsyncStreamT], - ) -> _AsyncStreamT: - ... + ) -> _AsyncStreamT: ... @overload async def post( @@ -1714,12 +1849,12 @@ async def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, stream: bool, stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: - ... + ) -> ResponseT | _AsyncStreamT: ... async def post( self, @@ -1727,13 +1862,25 @@ async def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) opts = FinalRequestOptions.construct( - method="post", url=path, json_data=body, files=await async_to_httpx_files(files), **options + method="post", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options ) return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) @@ -1743,9 +1890,29 @@ async def patch( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, + files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options) + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="patch", + url=path, + json_data=body, + content=content, + files=await async_to_httpx_files(files), + **options, + ) return await self.request(cast_to, opts) async def put( @@ -1754,11 +1921,23 @@ async def put( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) opts = FinalRequestOptions.construct( - method="put", url=path, json_data=body, files=await async_to_httpx_files(files), **options + method="put", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options ) return await self.request(cast_to, opts) @@ -1768,9 +1947,19 @@ async def delete( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options) + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options) return await self.request(cast_to, opts) def get_api_list( @@ -1794,8 +1983,8 @@ def make_request_options( extra_query: Query | None = None, extra_body: Body | None = None, idempotency_key: str | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - post_parser: PostParser | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + post_parser: PostParser | NotGiven = not_given, ) -> RequestOptions: """Create a dict of type RequestOptions without keys of NotGiven values.""" options: RequestOptions = {} @@ -1824,6 +2013,11 @@ def make_request_options( return options +class ForceMultipartDict(Dict[str, None]): + def __bool__(self) -> bool: + return True + + class OtherPlatform: def __init__(self, name: str) -> None: self.name = name @@ -1891,11 +2085,11 @@ def get_platform() -> Platform: @lru_cache(maxsize=None) -def platform_headers(version: str) -> Dict[str, str]: +def platform_headers(version: str, *, platform: Platform | None) -> Dict[str, str]: return { "X-Stainless-Lang": "python", "X-Stainless-Package-Version": version, - "X-Stainless-OS": str(get_platform()), + "X-Stainless-OS": str(platform or get_platform()), "X-Stainless-Arch": str(get_architecture()), "X-Stainless-Runtime": get_python_runtime(), "X-Stainless-Runtime-Version": get_python_version(), @@ -1930,7 +2124,6 @@ def get_python_version() -> str: def get_architecture() -> Arch: try: - python_bitness, _ = platform.architecture() machine = platform.machine().lower() except Exception: return "unknown" @@ -1946,7 +2139,7 @@ def get_architecture() -> Arch: return "x64" # TODO: untested - if python_bitness == "32bit": + if sys.maxsize <= 2**32: return "x32" if machine: diff --git a/src/orb/_client.py b/src/orb/_client.py index d43688ae..c77c4b52 100644 --- a/src/orb/_client.py +++ b/src/orb/_client.py @@ -3,27 +3,29 @@ from __future__ import annotations import os -from typing import Any, Union, Mapping +from typing import TYPE_CHECKING, Any, Mapping from typing_extensions import Self, override import httpx -from . import resources, _exceptions +from . import _exceptions from ._qs import Querystring from ._types import ( - NOT_GIVEN, Omit, Timeout, NotGiven, Transport, ProxiesTypes, RequestOptions, + not_given, ) from ._utils import ( is_given, is_mapping, + is_mapping_t, get_async_library, ) +from ._compat import cached_property from ._version import __version__ from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import OrbError, APIStatusError @@ -33,49 +35,72 @@ AsyncAPIClient, ) -__all__ = [ - "Timeout", - "Transport", - "ProxiesTypes", - "RequestOptions", - "resources", - "Orb", - "AsyncOrb", - "Client", - "AsyncClient", -] +if TYPE_CHECKING: + from .resources import ( + beta, + items, + plans, + alerts, + events, + prices, + coupons, + metrics, + invoices, + licenses, + customers, + top_level, + credit_notes, + credit_blocks, + license_types, + subscriptions, + invoice_line_items, + subscription_changes, + dimensional_price_groups, + ) + from .resources.items import Items, AsyncItems + from .resources.alerts import Alerts, AsyncAlerts + from .resources.metrics import Metrics, AsyncMetrics + from .resources.invoices import Invoices, AsyncInvoices + from .resources.beta.beta import Beta, AsyncBeta + from .resources.top_level import TopLevel, AsyncTopLevel + from .resources.plans.plans import Plans, AsyncPlans + from .resources.credit_notes import CreditNotes, AsyncCreditNotes + from .resources.credit_blocks import CreditBlocks, AsyncCreditBlocks + from .resources.events.events import Events, AsyncEvents + from .resources.license_types import LicenseTypes, AsyncLicenseTypes + from .resources.prices.prices import Prices, AsyncPrices + from .resources.subscriptions import Subscriptions, AsyncSubscriptions + from .resources.coupons.coupons import Coupons, AsyncCoupons + from .resources.licenses.licenses import Licenses, AsyncLicenses + from .resources.invoice_line_items import InvoiceLineItems, AsyncInvoiceLineItems + from .resources.customers.customers import Customers, AsyncCustomers + from .resources.subscription_changes import SubscriptionChanges, AsyncSubscriptionChanges + from .resources.dimensional_price_groups.dimensional_price_groups import ( + DimensionalPriceGroups, + AsyncDimensionalPriceGroups, + ) + +__all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Orb", "AsyncOrb", "Client", "AsyncClient"] class Orb(SyncAPIClient): - top_level: resources.TopLevel - coupons: resources.Coupons - credit_notes: resources.CreditNotes - customers: resources.Customers - events: resources.Events - invoice_line_items: resources.InvoiceLineItems - invoices: resources.Invoices - items: resources.Items - metrics: resources.Metrics - plans: resources.Plans - prices: resources.Prices - subscriptions: resources.Subscriptions - beta: resources.Beta - with_raw_response: OrbWithRawResponse - with_streaming_response: OrbWithStreamedResponse - # client options api_key: str + webhook_secret: str | None def __init__( self, *, api_key: str | None = None, + webhook_secret: str | None = None, base_url: str | httpx.URL | None = None, - timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, - # Configure a custom httpx client. See the [httpx documentation](https://www.python-httpx.org/api/#client) for more details. + # Configure a custom httpx client. + # We provide a `DefaultHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`. + # See the [httpx documentation](https://www.python-httpx.org/api/#client) for more details. http_client: httpx.Client | None = None, # Enable or disable schema validation for data returned by the API. # When enabled an error APIResponseValidationError is raised @@ -87,9 +112,11 @@ def __init__( # part of our public interface in the future. _strict_response_validation: bool = False, ) -> None: - """Construct a new synchronous orb client instance. + """Construct a new synchronous Orb client instance. - This automatically infers the `api_key` argument from the `ORB_API_KEY` environment variable if it is not provided. + This automatically infers the following arguments from their corresponding environment variables if they are not provided: + - `api_key` from `ORB_API_KEY` + - `webhook_secret` from `ORB_WEBHOOK_SECRET` """ if api_key is None: api_key = os.environ.get("ORB_API_KEY") @@ -99,11 +126,24 @@ def __init__( ) self.api_key = api_key + if webhook_secret is None: + webhook_secret = os.environ.get("ORB_WEBHOOK_SECRET") + self.webhook_secret = webhook_secret + if base_url is None: base_url = os.environ.get("ORB_BASE_URL") if base_url is None: base_url = f"https://api.withorb.com/v1" + custom_headers_env = os.environ.get("ORB_CUSTOM_HEADERS") + if custom_headers_env is not None: + parsed: dict[str, str] = {} + for line in custom_headers_env.split("\n"): + colon = line.find(":") + if colon >= 0: + parsed[line[:colon].strip()] = line[colon + 1 :].strip() + default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})} + super().__init__( version=__version__, base_url=base_url, @@ -117,21 +157,208 @@ def __init__( self._idempotency_header = "Idempotency-Key" - self.top_level = resources.TopLevel(self) - self.coupons = resources.Coupons(self) - self.credit_notes = resources.CreditNotes(self) - self.customers = resources.Customers(self) - self.events = resources.Events(self) - self.invoice_line_items = resources.InvoiceLineItems(self) - self.invoices = resources.Invoices(self) - self.items = resources.Items(self) - self.metrics = resources.Metrics(self) - self.plans = resources.Plans(self) - self.prices = resources.Prices(self) - self.subscriptions = resources.Subscriptions(self) - self.beta = resources.Beta(self) - self.with_raw_response = OrbWithRawResponse(self) - self.with_streaming_response = OrbWithStreamedResponse(self) + @cached_property + def top_level(self) -> TopLevel: + from .resources.top_level import TopLevel + + return TopLevel(self) + + @cached_property + def beta(self) -> Beta: + """ + The [Plan](/core-concepts#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). + """ + from .resources.beta import Beta + + return Beta(self) + + @cached_property + def coupons(self) -> Coupons: + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ + from .resources.coupons import Coupons + + return Coupons(self) + + @cached_property + def credit_notes(self) -> CreditNotes: + """ + The [Credit Note](/invoicing/credit-notes) resource represents a credit that has been applied to a + particular invoice. + """ + from .resources.credit_notes import CreditNotes + + return CreditNotes(self) + + @cached_property + def customers(self) -> Customers: + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + from .resources.customers import Customers + + return Customers(self) + + @cached_property + def events(self) -> Events: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + from .resources.events import Events + + return Events(self) + + @cached_property + def invoice_line_items(self) -> InvoiceLineItems: + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + from .resources.invoice_line_items import InvoiceLineItems + + return InvoiceLineItems(self) + + @cached_property + def invoices(self) -> Invoices: + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + from .resources.invoices import Invoices + + return Invoices(self) + + @cached_property + def items(self) -> Items: + """The Item resource represents a sellable product or good. + + Items are associated with all line items, billable metrics, + and prices and are used for defining external sync behavior for invoices and tax calculation purposes. + """ + from .resources.items import Items + + return Items(self) + + @cached_property + def metrics(self) -> Metrics: + """ + The Metric resource represents a calculation of a quantity based on events. + Metrics are defined by the query that transforms raw usage events into meaningful values for your customers. + """ + from .resources.metrics import Metrics + + return Metrics(self) + + @cached_property + def plans(self) -> Plans: + """ + The [Plan](/core-concepts#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). + """ + from .resources.plans import Plans + + return Plans(self) + + @cached_property + def prices(self) -> Prices: + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ + from .resources.prices import Prices + + return Prices(self) + + @cached_property + def subscriptions(self) -> Subscriptions: + from .resources.subscriptions import Subscriptions + + return Subscriptions(self) + + @cached_property + def alerts(self) -> Alerts: + """ + [Alerts within Orb](/product-catalog/configuring-alerts) monitor spending, + usage, or credit balance and trigger webhooks when a threshold is exceeded. + + Alerts created through the API can be scoped to either customers or subscriptions. + """ + from .resources.alerts import Alerts + + return Alerts(self) + + @cached_property + def dimensional_price_groups(self) -> DimensionalPriceGroups: + from .resources.dimensional_price_groups import DimensionalPriceGroups + + return DimensionalPriceGroups(self) + + @cached_property + def subscription_changes(self) -> SubscriptionChanges: + from .resources.subscription_changes import SubscriptionChanges + + return SubscriptionChanges(self) + + @cached_property + def credit_blocks(self) -> CreditBlocks: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ + from .resources.credit_blocks import CreditBlocks + + return CreditBlocks(self) + + @cached_property + def license_types(self) -> LicenseTypes: + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + from .resources.license_types import LicenseTypes + + return LicenseTypes(self) + + @cached_property + def licenses(self) -> Licenses: + from .resources.licenses import Licenses + + return Licenses(self) + + @cached_property + def with_raw_response(self) -> OrbWithRawResponse: + return OrbWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> OrbWithStreamedResponse: + return OrbWithStreamedResponse(self) @property @override @@ -157,10 +384,11 @@ def copy( self, *, api_key: str | None = None, + webhook_secret: str | None = None, base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.Client | None = None, - max_retries: int | NotGiven = NOT_GIVEN, + max_retries: int | NotGiven = not_given, default_headers: Mapping[str, str] | None = None, set_default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, @@ -191,6 +419,7 @@ def copy( http_client = http_client or self._client return self.__class__( api_key=api_key or self.api_key, + webhook_secret=webhook_secret or self.webhook_secret, base_url=base_url or self.base_url, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client, @@ -287,35 +516,23 @@ def _make_status_error( class AsyncOrb(AsyncAPIClient): - top_level: resources.AsyncTopLevel - coupons: resources.AsyncCoupons - credit_notes: resources.AsyncCreditNotes - customers: resources.AsyncCustomers - events: resources.AsyncEvents - invoice_line_items: resources.AsyncInvoiceLineItems - invoices: resources.AsyncInvoices - items: resources.AsyncItems - metrics: resources.AsyncMetrics - plans: resources.AsyncPlans - prices: resources.AsyncPrices - subscriptions: resources.AsyncSubscriptions - beta: resources.AsyncBeta - with_raw_response: AsyncOrbWithRawResponse - with_streaming_response: AsyncOrbWithStreamedResponse - # client options api_key: str + webhook_secret: str | None def __init__( self, *, api_key: str | None = None, + webhook_secret: str | None = None, base_url: str | httpx.URL | None = None, - timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, - # Configure a custom httpx client. See the [httpx documentation](https://www.python-httpx.org/api/#asyncclient) for more details. + # Configure a custom httpx client. + # We provide a `DefaultAsyncHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`. + # See the [httpx documentation](https://www.python-httpx.org/api/#asyncclient) for more details. http_client: httpx.AsyncClient | None = None, # Enable or disable schema validation for data returned by the API. # When enabled an error APIResponseValidationError is raised @@ -327,9 +544,11 @@ def __init__( # part of our public interface in the future. _strict_response_validation: bool = False, ) -> None: - """Construct a new async orb client instance. + """Construct a new async AsyncOrb client instance. - This automatically infers the `api_key` argument from the `ORB_API_KEY` environment variable if it is not provided. + This automatically infers the following arguments from their corresponding environment variables if they are not provided: + - `api_key` from `ORB_API_KEY` + - `webhook_secret` from `ORB_WEBHOOK_SECRET` """ if api_key is None: api_key = os.environ.get("ORB_API_KEY") @@ -339,11 +558,24 @@ def __init__( ) self.api_key = api_key + if webhook_secret is None: + webhook_secret = os.environ.get("ORB_WEBHOOK_SECRET") + self.webhook_secret = webhook_secret + if base_url is None: base_url = os.environ.get("ORB_BASE_URL") if base_url is None: base_url = f"https://api.withorb.com/v1" + custom_headers_env = os.environ.get("ORB_CUSTOM_HEADERS") + if custom_headers_env is not None: + parsed: dict[str, str] = {} + for line in custom_headers_env.split("\n"): + colon = line.find(":") + if colon >= 0: + parsed[line[:colon].strip()] = line[colon + 1 :].strip() + default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})} + super().__init__( version=__version__, base_url=base_url, @@ -357,21 +589,208 @@ def __init__( self._idempotency_header = "Idempotency-Key" - self.top_level = resources.AsyncTopLevel(self) - self.coupons = resources.AsyncCoupons(self) - self.credit_notes = resources.AsyncCreditNotes(self) - self.customers = resources.AsyncCustomers(self) - self.events = resources.AsyncEvents(self) - self.invoice_line_items = resources.AsyncInvoiceLineItems(self) - self.invoices = resources.AsyncInvoices(self) - self.items = resources.AsyncItems(self) - self.metrics = resources.AsyncMetrics(self) - self.plans = resources.AsyncPlans(self) - self.prices = resources.AsyncPrices(self) - self.subscriptions = resources.AsyncSubscriptions(self) - self.beta = resources.AsyncBeta(self) - self.with_raw_response = AsyncOrbWithRawResponse(self) - self.with_streaming_response = AsyncOrbWithStreamedResponse(self) + @cached_property + def top_level(self) -> AsyncTopLevel: + from .resources.top_level import AsyncTopLevel + + return AsyncTopLevel(self) + + @cached_property + def beta(self) -> AsyncBeta: + """ + The [Plan](/core-concepts#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). + """ + from .resources.beta import AsyncBeta + + return AsyncBeta(self) + + @cached_property + def coupons(self) -> AsyncCoupons: + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ + from .resources.coupons import AsyncCoupons + + return AsyncCoupons(self) + + @cached_property + def credit_notes(self) -> AsyncCreditNotes: + """ + The [Credit Note](/invoicing/credit-notes) resource represents a credit that has been applied to a + particular invoice. + """ + from .resources.credit_notes import AsyncCreditNotes + + return AsyncCreditNotes(self) + + @cached_property + def customers(self) -> AsyncCustomers: + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + from .resources.customers import AsyncCustomers + + return AsyncCustomers(self) + + @cached_property + def events(self) -> AsyncEvents: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + from .resources.events import AsyncEvents + + return AsyncEvents(self) + + @cached_property + def invoice_line_items(self) -> AsyncInvoiceLineItems: + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + from .resources.invoice_line_items import AsyncInvoiceLineItems + + return AsyncInvoiceLineItems(self) + + @cached_property + def invoices(self) -> AsyncInvoices: + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + from .resources.invoices import AsyncInvoices + + return AsyncInvoices(self) + + @cached_property + def items(self) -> AsyncItems: + """The Item resource represents a sellable product or good. + + Items are associated with all line items, billable metrics, + and prices and are used for defining external sync behavior for invoices and tax calculation purposes. + """ + from .resources.items import AsyncItems + + return AsyncItems(self) + + @cached_property + def metrics(self) -> AsyncMetrics: + """ + The Metric resource represents a calculation of a quantity based on events. + Metrics are defined by the query that transforms raw usage events into meaningful values for your customers. + """ + from .resources.metrics import AsyncMetrics + + return AsyncMetrics(self) + + @cached_property + def plans(self) -> AsyncPlans: + """ + The [Plan](/core-concepts#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). + """ + from .resources.plans import AsyncPlans + + return AsyncPlans(self) + + @cached_property + def prices(self) -> AsyncPrices: + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ + from .resources.prices import AsyncPrices + + return AsyncPrices(self) + + @cached_property + def subscriptions(self) -> AsyncSubscriptions: + from .resources.subscriptions import AsyncSubscriptions + + return AsyncSubscriptions(self) + + @cached_property + def alerts(self) -> AsyncAlerts: + """ + [Alerts within Orb](/product-catalog/configuring-alerts) monitor spending, + usage, or credit balance and trigger webhooks when a threshold is exceeded. + + Alerts created through the API can be scoped to either customers or subscriptions. + """ + from .resources.alerts import AsyncAlerts + + return AsyncAlerts(self) + + @cached_property + def dimensional_price_groups(self) -> AsyncDimensionalPriceGroups: + from .resources.dimensional_price_groups import AsyncDimensionalPriceGroups + + return AsyncDimensionalPriceGroups(self) + + @cached_property + def subscription_changes(self) -> AsyncSubscriptionChanges: + from .resources.subscription_changes import AsyncSubscriptionChanges + + return AsyncSubscriptionChanges(self) + + @cached_property + def credit_blocks(self) -> AsyncCreditBlocks: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ + from .resources.credit_blocks import AsyncCreditBlocks + + return AsyncCreditBlocks(self) + + @cached_property + def license_types(self) -> AsyncLicenseTypes: + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + from .resources.license_types import AsyncLicenseTypes + + return AsyncLicenseTypes(self) + + @cached_property + def licenses(self) -> AsyncLicenses: + from .resources.licenses import AsyncLicenses + + return AsyncLicenses(self) + + @cached_property + def with_raw_response(self) -> AsyncOrbWithRawResponse: + return AsyncOrbWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncOrbWithStreamedResponse: + return AsyncOrbWithStreamedResponse(self) @property @override @@ -397,10 +816,11 @@ def copy( self, *, api_key: str | None = None, + webhook_secret: str | None = None, base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.AsyncClient | None = None, - max_retries: int | NotGiven = NOT_GIVEN, + max_retries: int | NotGiven = not_given, default_headers: Mapping[str, str] | None = None, set_default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, @@ -431,6 +851,7 @@ def copy( http_client = http_client or self._client return self.__class__( api_key=api_key or self.api_key, + webhook_secret=webhook_secret or self.webhook_secret, base_url=base_url or self.base_url, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client, @@ -527,71 +948,811 @@ def _make_status_error( class OrbWithRawResponse: + _client: Orb + def __init__(self, client: Orb) -> None: - self.top_level = resources.TopLevelWithRawResponse(client.top_level) - self.coupons = resources.CouponsWithRawResponse(client.coupons) - self.credit_notes = resources.CreditNotesWithRawResponse(client.credit_notes) - self.customers = resources.CustomersWithRawResponse(client.customers) - self.events = resources.EventsWithRawResponse(client.events) - self.invoice_line_items = resources.InvoiceLineItemsWithRawResponse(client.invoice_line_items) - self.invoices = resources.InvoicesWithRawResponse(client.invoices) - self.items = resources.ItemsWithRawResponse(client.items) - self.metrics = resources.MetricsWithRawResponse(client.metrics) - self.plans = resources.PlansWithRawResponse(client.plans) - self.prices = resources.PricesWithRawResponse(client.prices) - self.subscriptions = resources.SubscriptionsWithRawResponse(client.subscriptions) - self.beta = resources.BetaWithRawResponse(client.beta) + self._client = client + + @cached_property + def top_level(self) -> top_level.TopLevelWithRawResponse: + from .resources.top_level import TopLevelWithRawResponse + + return TopLevelWithRawResponse(self._client.top_level) + + @cached_property + def beta(self) -> beta.BetaWithRawResponse: + """ + The [Plan](/core-concepts#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). + """ + from .resources.beta import BetaWithRawResponse + + return BetaWithRawResponse(self._client.beta) + + @cached_property + def coupons(self) -> coupons.CouponsWithRawResponse: + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ + from .resources.coupons import CouponsWithRawResponse + + return CouponsWithRawResponse(self._client.coupons) + + @cached_property + def credit_notes(self) -> credit_notes.CreditNotesWithRawResponse: + """ + The [Credit Note](/invoicing/credit-notes) resource represents a credit that has been applied to a + particular invoice. + """ + from .resources.credit_notes import CreditNotesWithRawResponse + + return CreditNotesWithRawResponse(self._client.credit_notes) + + @cached_property + def customers(self) -> customers.CustomersWithRawResponse: + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + from .resources.customers import CustomersWithRawResponse + + return CustomersWithRawResponse(self._client.customers) + + @cached_property + def events(self) -> events.EventsWithRawResponse: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + from .resources.events import EventsWithRawResponse + + return EventsWithRawResponse(self._client.events) + + @cached_property + def invoice_line_items(self) -> invoice_line_items.InvoiceLineItemsWithRawResponse: + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + from .resources.invoice_line_items import InvoiceLineItemsWithRawResponse + + return InvoiceLineItemsWithRawResponse(self._client.invoice_line_items) + + @cached_property + def invoices(self) -> invoices.InvoicesWithRawResponse: + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + from .resources.invoices import InvoicesWithRawResponse + + return InvoicesWithRawResponse(self._client.invoices) + + @cached_property + def items(self) -> items.ItemsWithRawResponse: + """The Item resource represents a sellable product or good. + + Items are associated with all line items, billable metrics, + and prices and are used for defining external sync behavior for invoices and tax calculation purposes. + """ + from .resources.items import ItemsWithRawResponse + + return ItemsWithRawResponse(self._client.items) + + @cached_property + def metrics(self) -> metrics.MetricsWithRawResponse: + """ + The Metric resource represents a calculation of a quantity based on events. + Metrics are defined by the query that transforms raw usage events into meaningful values for your customers. + """ + from .resources.metrics import MetricsWithRawResponse + + return MetricsWithRawResponse(self._client.metrics) + + @cached_property + def plans(self) -> plans.PlansWithRawResponse: + """ + The [Plan](/core-concepts#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). + """ + from .resources.plans import PlansWithRawResponse + + return PlansWithRawResponse(self._client.plans) + + @cached_property + def prices(self) -> prices.PricesWithRawResponse: + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ + from .resources.prices import PricesWithRawResponse + + return PricesWithRawResponse(self._client.prices) + + @cached_property + def subscriptions(self) -> subscriptions.SubscriptionsWithRawResponse: + from .resources.subscriptions import SubscriptionsWithRawResponse + + return SubscriptionsWithRawResponse(self._client.subscriptions) + + @cached_property + def alerts(self) -> alerts.AlertsWithRawResponse: + """ + [Alerts within Orb](/product-catalog/configuring-alerts) monitor spending, + usage, or credit balance and trigger webhooks when a threshold is exceeded. + + Alerts created through the API can be scoped to either customers or subscriptions. + """ + from .resources.alerts import AlertsWithRawResponse + + return AlertsWithRawResponse(self._client.alerts) + + @cached_property + def dimensional_price_groups(self) -> dimensional_price_groups.DimensionalPriceGroupsWithRawResponse: + from .resources.dimensional_price_groups import DimensionalPriceGroupsWithRawResponse + + return DimensionalPriceGroupsWithRawResponse(self._client.dimensional_price_groups) + + @cached_property + def subscription_changes(self) -> subscription_changes.SubscriptionChangesWithRawResponse: + from .resources.subscription_changes import SubscriptionChangesWithRawResponse + + return SubscriptionChangesWithRawResponse(self._client.subscription_changes) + + @cached_property + def credit_blocks(self) -> credit_blocks.CreditBlocksWithRawResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ + from .resources.credit_blocks import CreditBlocksWithRawResponse + + return CreditBlocksWithRawResponse(self._client.credit_blocks) + + @cached_property + def license_types(self) -> license_types.LicenseTypesWithRawResponse: + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + from .resources.license_types import LicenseTypesWithRawResponse + + return LicenseTypesWithRawResponse(self._client.license_types) + + @cached_property + def licenses(self) -> licenses.LicensesWithRawResponse: + from .resources.licenses import LicensesWithRawResponse + + return LicensesWithRawResponse(self._client.licenses) class AsyncOrbWithRawResponse: + _client: AsyncOrb + def __init__(self, client: AsyncOrb) -> None: - self.top_level = resources.AsyncTopLevelWithRawResponse(client.top_level) - self.coupons = resources.AsyncCouponsWithRawResponse(client.coupons) - self.credit_notes = resources.AsyncCreditNotesWithRawResponse(client.credit_notes) - self.customers = resources.AsyncCustomersWithRawResponse(client.customers) - self.events = resources.AsyncEventsWithRawResponse(client.events) - self.invoice_line_items = resources.AsyncInvoiceLineItemsWithRawResponse(client.invoice_line_items) - self.invoices = resources.AsyncInvoicesWithRawResponse(client.invoices) - self.items = resources.AsyncItemsWithRawResponse(client.items) - self.metrics = resources.AsyncMetricsWithRawResponse(client.metrics) - self.plans = resources.AsyncPlansWithRawResponse(client.plans) - self.prices = resources.AsyncPricesWithRawResponse(client.prices) - self.subscriptions = resources.AsyncSubscriptionsWithRawResponse(client.subscriptions) - self.beta = resources.AsyncBetaWithRawResponse(client.beta) + self._client = client + + @cached_property + def top_level(self) -> top_level.AsyncTopLevelWithRawResponse: + from .resources.top_level import AsyncTopLevelWithRawResponse + + return AsyncTopLevelWithRawResponse(self._client.top_level) + + @cached_property + def beta(self) -> beta.AsyncBetaWithRawResponse: + """ + The [Plan](/core-concepts#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). + """ + from .resources.beta import AsyncBetaWithRawResponse + + return AsyncBetaWithRawResponse(self._client.beta) + + @cached_property + def coupons(self) -> coupons.AsyncCouponsWithRawResponse: + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ + from .resources.coupons import AsyncCouponsWithRawResponse + + return AsyncCouponsWithRawResponse(self._client.coupons) + + @cached_property + def credit_notes(self) -> credit_notes.AsyncCreditNotesWithRawResponse: + """ + The [Credit Note](/invoicing/credit-notes) resource represents a credit that has been applied to a + particular invoice. + """ + from .resources.credit_notes import AsyncCreditNotesWithRawResponse + + return AsyncCreditNotesWithRawResponse(self._client.credit_notes) + + @cached_property + def customers(self) -> customers.AsyncCustomersWithRawResponse: + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + from .resources.customers import AsyncCustomersWithRawResponse + + return AsyncCustomersWithRawResponse(self._client.customers) + + @cached_property + def events(self) -> events.AsyncEventsWithRawResponse: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + from .resources.events import AsyncEventsWithRawResponse + + return AsyncEventsWithRawResponse(self._client.events) + + @cached_property + def invoice_line_items(self) -> invoice_line_items.AsyncInvoiceLineItemsWithRawResponse: + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + from .resources.invoice_line_items import AsyncInvoiceLineItemsWithRawResponse + + return AsyncInvoiceLineItemsWithRawResponse(self._client.invoice_line_items) + + @cached_property + def invoices(self) -> invoices.AsyncInvoicesWithRawResponse: + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + from .resources.invoices import AsyncInvoicesWithRawResponse + + return AsyncInvoicesWithRawResponse(self._client.invoices) + + @cached_property + def items(self) -> items.AsyncItemsWithRawResponse: + """The Item resource represents a sellable product or good. + + Items are associated with all line items, billable metrics, + and prices and are used for defining external sync behavior for invoices and tax calculation purposes. + """ + from .resources.items import AsyncItemsWithRawResponse + + return AsyncItemsWithRawResponse(self._client.items) + + @cached_property + def metrics(self) -> metrics.AsyncMetricsWithRawResponse: + """ + The Metric resource represents a calculation of a quantity based on events. + Metrics are defined by the query that transforms raw usage events into meaningful values for your customers. + """ + from .resources.metrics import AsyncMetricsWithRawResponse + + return AsyncMetricsWithRawResponse(self._client.metrics) + + @cached_property + def plans(self) -> plans.AsyncPlansWithRawResponse: + """ + The [Plan](/core-concepts#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). + """ + from .resources.plans import AsyncPlansWithRawResponse + + return AsyncPlansWithRawResponse(self._client.plans) + + @cached_property + def prices(self) -> prices.AsyncPricesWithRawResponse: + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ + from .resources.prices import AsyncPricesWithRawResponse + + return AsyncPricesWithRawResponse(self._client.prices) + + @cached_property + def subscriptions(self) -> subscriptions.AsyncSubscriptionsWithRawResponse: + from .resources.subscriptions import AsyncSubscriptionsWithRawResponse + + return AsyncSubscriptionsWithRawResponse(self._client.subscriptions) + + @cached_property + def alerts(self) -> alerts.AsyncAlertsWithRawResponse: + """ + [Alerts within Orb](/product-catalog/configuring-alerts) monitor spending, + usage, or credit balance and trigger webhooks when a threshold is exceeded. + + Alerts created through the API can be scoped to either customers or subscriptions. + """ + from .resources.alerts import AsyncAlertsWithRawResponse + + return AsyncAlertsWithRawResponse(self._client.alerts) + + @cached_property + def dimensional_price_groups(self) -> dimensional_price_groups.AsyncDimensionalPriceGroupsWithRawResponse: + from .resources.dimensional_price_groups import AsyncDimensionalPriceGroupsWithRawResponse + + return AsyncDimensionalPriceGroupsWithRawResponse(self._client.dimensional_price_groups) + + @cached_property + def subscription_changes(self) -> subscription_changes.AsyncSubscriptionChangesWithRawResponse: + from .resources.subscription_changes import AsyncSubscriptionChangesWithRawResponse + + return AsyncSubscriptionChangesWithRawResponse(self._client.subscription_changes) + + @cached_property + def credit_blocks(self) -> credit_blocks.AsyncCreditBlocksWithRawResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ + from .resources.credit_blocks import AsyncCreditBlocksWithRawResponse + + return AsyncCreditBlocksWithRawResponse(self._client.credit_blocks) + + @cached_property + def license_types(self) -> license_types.AsyncLicenseTypesWithRawResponse: + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + from .resources.license_types import AsyncLicenseTypesWithRawResponse + + return AsyncLicenseTypesWithRawResponse(self._client.license_types) + + @cached_property + def licenses(self) -> licenses.AsyncLicensesWithRawResponse: + from .resources.licenses import AsyncLicensesWithRawResponse + + return AsyncLicensesWithRawResponse(self._client.licenses) class OrbWithStreamedResponse: + _client: Orb + def __init__(self, client: Orb) -> None: - self.top_level = resources.TopLevelWithStreamingResponse(client.top_level) - self.coupons = resources.CouponsWithStreamingResponse(client.coupons) - self.credit_notes = resources.CreditNotesWithStreamingResponse(client.credit_notes) - self.customers = resources.CustomersWithStreamingResponse(client.customers) - self.events = resources.EventsWithStreamingResponse(client.events) - self.invoice_line_items = resources.InvoiceLineItemsWithStreamingResponse(client.invoice_line_items) - self.invoices = resources.InvoicesWithStreamingResponse(client.invoices) - self.items = resources.ItemsWithStreamingResponse(client.items) - self.metrics = resources.MetricsWithStreamingResponse(client.metrics) - self.plans = resources.PlansWithStreamingResponse(client.plans) - self.prices = resources.PricesWithStreamingResponse(client.prices) - self.subscriptions = resources.SubscriptionsWithStreamingResponse(client.subscriptions) - self.beta = resources.BetaWithStreamingResponse(client.beta) + self._client = client + + @cached_property + def top_level(self) -> top_level.TopLevelWithStreamingResponse: + from .resources.top_level import TopLevelWithStreamingResponse + + return TopLevelWithStreamingResponse(self._client.top_level) + + @cached_property + def beta(self) -> beta.BetaWithStreamingResponse: + """ + The [Plan](/core-concepts#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). + """ + from .resources.beta import BetaWithStreamingResponse + + return BetaWithStreamingResponse(self._client.beta) + + @cached_property + def coupons(self) -> coupons.CouponsWithStreamingResponse: + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ + from .resources.coupons import CouponsWithStreamingResponse + + return CouponsWithStreamingResponse(self._client.coupons) + + @cached_property + def credit_notes(self) -> credit_notes.CreditNotesWithStreamingResponse: + """ + The [Credit Note](/invoicing/credit-notes) resource represents a credit that has been applied to a + particular invoice. + """ + from .resources.credit_notes import CreditNotesWithStreamingResponse + + return CreditNotesWithStreamingResponse(self._client.credit_notes) + + @cached_property + def customers(self) -> customers.CustomersWithStreamingResponse: + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + from .resources.customers import CustomersWithStreamingResponse + + return CustomersWithStreamingResponse(self._client.customers) + + @cached_property + def events(self) -> events.EventsWithStreamingResponse: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + from .resources.events import EventsWithStreamingResponse + + return EventsWithStreamingResponse(self._client.events) + + @cached_property + def invoice_line_items(self) -> invoice_line_items.InvoiceLineItemsWithStreamingResponse: + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + from .resources.invoice_line_items import InvoiceLineItemsWithStreamingResponse + + return InvoiceLineItemsWithStreamingResponse(self._client.invoice_line_items) + + @cached_property + def invoices(self) -> invoices.InvoicesWithStreamingResponse: + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + from .resources.invoices import InvoicesWithStreamingResponse + + return InvoicesWithStreamingResponse(self._client.invoices) + + @cached_property + def items(self) -> items.ItemsWithStreamingResponse: + """The Item resource represents a sellable product or good. + + Items are associated with all line items, billable metrics, + and prices and are used for defining external sync behavior for invoices and tax calculation purposes. + """ + from .resources.items import ItemsWithStreamingResponse + + return ItemsWithStreamingResponse(self._client.items) + + @cached_property + def metrics(self) -> metrics.MetricsWithStreamingResponse: + """ + The Metric resource represents a calculation of a quantity based on events. + Metrics are defined by the query that transforms raw usage events into meaningful values for your customers. + """ + from .resources.metrics import MetricsWithStreamingResponse + + return MetricsWithStreamingResponse(self._client.metrics) + + @cached_property + def plans(self) -> plans.PlansWithStreamingResponse: + """ + The [Plan](/core-concepts#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). + """ + from .resources.plans import PlansWithStreamingResponse + + return PlansWithStreamingResponse(self._client.plans) + + @cached_property + def prices(self) -> prices.PricesWithStreamingResponse: + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ + from .resources.prices import PricesWithStreamingResponse + + return PricesWithStreamingResponse(self._client.prices) + + @cached_property + def subscriptions(self) -> subscriptions.SubscriptionsWithStreamingResponse: + from .resources.subscriptions import SubscriptionsWithStreamingResponse + + return SubscriptionsWithStreamingResponse(self._client.subscriptions) + + @cached_property + def alerts(self) -> alerts.AlertsWithStreamingResponse: + """ + [Alerts within Orb](/product-catalog/configuring-alerts) monitor spending, + usage, or credit balance and trigger webhooks when a threshold is exceeded. + + Alerts created through the API can be scoped to either customers or subscriptions. + """ + from .resources.alerts import AlertsWithStreamingResponse + + return AlertsWithStreamingResponse(self._client.alerts) + + @cached_property + def dimensional_price_groups(self) -> dimensional_price_groups.DimensionalPriceGroupsWithStreamingResponse: + from .resources.dimensional_price_groups import DimensionalPriceGroupsWithStreamingResponse + + return DimensionalPriceGroupsWithStreamingResponse(self._client.dimensional_price_groups) + + @cached_property + def subscription_changes(self) -> subscription_changes.SubscriptionChangesWithStreamingResponse: + from .resources.subscription_changes import SubscriptionChangesWithStreamingResponse + + return SubscriptionChangesWithStreamingResponse(self._client.subscription_changes) + + @cached_property + def credit_blocks(self) -> credit_blocks.CreditBlocksWithStreamingResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ + from .resources.credit_blocks import CreditBlocksWithStreamingResponse + + return CreditBlocksWithStreamingResponse(self._client.credit_blocks) + + @cached_property + def license_types(self) -> license_types.LicenseTypesWithStreamingResponse: + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + from .resources.license_types import LicenseTypesWithStreamingResponse + + return LicenseTypesWithStreamingResponse(self._client.license_types) + + @cached_property + def licenses(self) -> licenses.LicensesWithStreamingResponse: + from .resources.licenses import LicensesWithStreamingResponse + + return LicensesWithStreamingResponse(self._client.licenses) class AsyncOrbWithStreamedResponse: + _client: AsyncOrb + def __init__(self, client: AsyncOrb) -> None: - self.top_level = resources.AsyncTopLevelWithStreamingResponse(client.top_level) - self.coupons = resources.AsyncCouponsWithStreamingResponse(client.coupons) - self.credit_notes = resources.AsyncCreditNotesWithStreamingResponse(client.credit_notes) - self.customers = resources.AsyncCustomersWithStreamingResponse(client.customers) - self.events = resources.AsyncEventsWithStreamingResponse(client.events) - self.invoice_line_items = resources.AsyncInvoiceLineItemsWithStreamingResponse(client.invoice_line_items) - self.invoices = resources.AsyncInvoicesWithStreamingResponse(client.invoices) - self.items = resources.AsyncItemsWithStreamingResponse(client.items) - self.metrics = resources.AsyncMetricsWithStreamingResponse(client.metrics) - self.plans = resources.AsyncPlansWithStreamingResponse(client.plans) - self.prices = resources.AsyncPricesWithStreamingResponse(client.prices) - self.subscriptions = resources.AsyncSubscriptionsWithStreamingResponse(client.subscriptions) - self.beta = resources.AsyncBetaWithStreamingResponse(client.beta) + self._client = client + + @cached_property + def top_level(self) -> top_level.AsyncTopLevelWithStreamingResponse: + from .resources.top_level import AsyncTopLevelWithStreamingResponse + + return AsyncTopLevelWithStreamingResponse(self._client.top_level) + + @cached_property + def beta(self) -> beta.AsyncBetaWithStreamingResponse: + """ + The [Plan](/core-concepts#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). + """ + from .resources.beta import AsyncBetaWithStreamingResponse + + return AsyncBetaWithStreamingResponse(self._client.beta) + + @cached_property + def coupons(self) -> coupons.AsyncCouponsWithStreamingResponse: + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ + from .resources.coupons import AsyncCouponsWithStreamingResponse + + return AsyncCouponsWithStreamingResponse(self._client.coupons) + + @cached_property + def credit_notes(self) -> credit_notes.AsyncCreditNotesWithStreamingResponse: + """ + The [Credit Note](/invoicing/credit-notes) resource represents a credit that has been applied to a + particular invoice. + """ + from .resources.credit_notes import AsyncCreditNotesWithStreamingResponse + + return AsyncCreditNotesWithStreamingResponse(self._client.credit_notes) + + @cached_property + def customers(self) -> customers.AsyncCustomersWithStreamingResponse: + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + from .resources.customers import AsyncCustomersWithStreamingResponse + + return AsyncCustomersWithStreamingResponse(self._client.customers) + + @cached_property + def events(self) -> events.AsyncEventsWithStreamingResponse: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + from .resources.events import AsyncEventsWithStreamingResponse + + return AsyncEventsWithStreamingResponse(self._client.events) + + @cached_property + def invoice_line_items(self) -> invoice_line_items.AsyncInvoiceLineItemsWithStreamingResponse: + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + from .resources.invoice_line_items import AsyncInvoiceLineItemsWithStreamingResponse + + return AsyncInvoiceLineItemsWithStreamingResponse(self._client.invoice_line_items) + + @cached_property + def invoices(self) -> invoices.AsyncInvoicesWithStreamingResponse: + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + from .resources.invoices import AsyncInvoicesWithStreamingResponse + + return AsyncInvoicesWithStreamingResponse(self._client.invoices) + + @cached_property + def items(self) -> items.AsyncItemsWithStreamingResponse: + """The Item resource represents a sellable product or good. + + Items are associated with all line items, billable metrics, + and prices and are used for defining external sync behavior for invoices and tax calculation purposes. + """ + from .resources.items import AsyncItemsWithStreamingResponse + + return AsyncItemsWithStreamingResponse(self._client.items) + + @cached_property + def metrics(self) -> metrics.AsyncMetricsWithStreamingResponse: + """ + The Metric resource represents a calculation of a quantity based on events. + Metrics are defined by the query that transforms raw usage events into meaningful values for your customers. + """ + from .resources.metrics import AsyncMetricsWithStreamingResponse + + return AsyncMetricsWithStreamingResponse(self._client.metrics) + + @cached_property + def plans(self) -> plans.AsyncPlansWithStreamingResponse: + """ + The [Plan](/core-concepts#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). + """ + from .resources.plans import AsyncPlansWithStreamingResponse + + return AsyncPlansWithStreamingResponse(self._client.plans) + + @cached_property + def prices(self) -> prices.AsyncPricesWithStreamingResponse: + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ + from .resources.prices import AsyncPricesWithStreamingResponse + + return AsyncPricesWithStreamingResponse(self._client.prices) + + @cached_property + def subscriptions(self) -> subscriptions.AsyncSubscriptionsWithStreamingResponse: + from .resources.subscriptions import AsyncSubscriptionsWithStreamingResponse + + return AsyncSubscriptionsWithStreamingResponse(self._client.subscriptions) + + @cached_property + def alerts(self) -> alerts.AsyncAlertsWithStreamingResponse: + """ + [Alerts within Orb](/product-catalog/configuring-alerts) monitor spending, + usage, or credit balance and trigger webhooks when a threshold is exceeded. + + Alerts created through the API can be scoped to either customers or subscriptions. + """ + from .resources.alerts import AsyncAlertsWithStreamingResponse + + return AsyncAlertsWithStreamingResponse(self._client.alerts) + + @cached_property + def dimensional_price_groups(self) -> dimensional_price_groups.AsyncDimensionalPriceGroupsWithStreamingResponse: + from .resources.dimensional_price_groups import AsyncDimensionalPriceGroupsWithStreamingResponse + + return AsyncDimensionalPriceGroupsWithStreamingResponse(self._client.dimensional_price_groups) + + @cached_property + def subscription_changes(self) -> subscription_changes.AsyncSubscriptionChangesWithStreamingResponse: + from .resources.subscription_changes import AsyncSubscriptionChangesWithStreamingResponse + + return AsyncSubscriptionChangesWithStreamingResponse(self._client.subscription_changes) + + @cached_property + def credit_blocks(self) -> credit_blocks.AsyncCreditBlocksWithStreamingResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ + from .resources.credit_blocks import AsyncCreditBlocksWithStreamingResponse + + return AsyncCreditBlocksWithStreamingResponse(self._client.credit_blocks) + + @cached_property + def license_types(self) -> license_types.AsyncLicenseTypesWithStreamingResponse: + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + from .resources.license_types import AsyncLicenseTypesWithStreamingResponse + + return AsyncLicenseTypesWithStreamingResponse(self._client.license_types) + + @cached_property + def licenses(self) -> licenses.AsyncLicensesWithStreamingResponse: + from .resources.licenses import AsyncLicensesWithStreamingResponse + + return AsyncLicensesWithStreamingResponse(self._client.licenses) Client = Orb diff --git a/src/orb/_compat.py b/src/orb/_compat.py index 74c7639b..e6690a4f 100644 --- a/src/orb/_compat.py +++ b/src/orb/_compat.py @@ -2,24 +2,23 @@ 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, TypedDict import pydantic from pydantic.fields import FieldInfo -from ._types import StrBytesIntFloat +from ._types import IncEx, StrBytesIntFloat _T = TypeVar("_T") _ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel) -# --------------- Pydantic v2 compatibility --------------- +# --------------- Pydantic v2, v3 compatibility --------------- # Pyright incorrectly reports some of our functions as overriding a method when they don't # pyright: reportIncompatibleMethodOverride=false -PYDANTIC_V2 = pydantic.VERSION.startswith("2.") +PYDANTIC_V1 = pydantic.VERSION.startswith("1.") -# v1 re-exports if TYPE_CHECKING: def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001 @@ -44,137 +43,150 @@ def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 ... else: - if PYDANTIC_V2: - from pydantic.v1.typing import ( + # v1 re-exports + if PYDANTIC_V1: + from pydantic.typing import ( get_args as get_args, is_union as is_union, get_origin as get_origin, is_typeddict as is_typeddict, is_literal_type as is_literal_type, ) - from pydantic.v1.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime + from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime else: - from pydantic.typing import ( + from ._utils import ( get_args as get_args, is_union as is_union, get_origin as get_origin, + parse_date as parse_date, is_typeddict as is_typeddict, + parse_datetime as parse_datetime, is_literal_type as is_literal_type, ) - from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime # refactored config if TYPE_CHECKING: from pydantic import ConfigDict as ConfigDict else: - if PYDANTIC_V2: - from pydantic import ConfigDict - else: + if PYDANTIC_V1: # TODO: provide an error message here? ConfigDict = None + else: + from pydantic import ConfigDict as ConfigDict # renamed methods / properties def parse_obj(model: type[_ModelT], value: object) -> _ModelT: - if PYDANTIC_V2: - return model.model_validate(value) - else: + if PYDANTIC_V1: return cast(_ModelT, model.parse_obj(value)) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + else: + return model.model_validate(value) def field_is_required(field: FieldInfo) -> bool: - if PYDANTIC_V2: - return field.is_required() - return field.required # type: ignore + if PYDANTIC_V1: + return field.required # type: ignore + return field.is_required() def field_get_default(field: FieldInfo) -> Any: value = field.get_default() - if PYDANTIC_V2: - from pydantic_core import PydanticUndefined - - if value == PydanticUndefined: - return None + if PYDANTIC_V1: return value + from pydantic_core import PydanticUndefined + + if value == PydanticUndefined: + return None return value def field_outer_type(field: FieldInfo) -> Any: - if PYDANTIC_V2: - return field.annotation - return field.outer_type_ # type: ignore + if PYDANTIC_V1: + return field.outer_type_ # type: ignore + return field.annotation def get_model_config(model: type[pydantic.BaseModel]) -> Any: - if PYDANTIC_V2: - return model.model_config - return model.__config__ # type: ignore + if PYDANTIC_V1: + return model.__config__ # type: ignore + return model.model_config def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]: - if PYDANTIC_V2: - return model.model_fields - return model.__fields__ # type: ignore + if PYDANTIC_V1: + return model.__fields__ # type: ignore + return model.model_fields -def model_copy(model: _ModelT) -> _ModelT: - if PYDANTIC_V2: - return model.model_copy() - return model.copy() # type: ignore +def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT: + if PYDANTIC_V1: + return model.copy(deep=deep) # type: ignore + return model.model_copy(deep=deep) def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: - if PYDANTIC_V2: - return model.model_dump_json(indent=indent) - return model.json(indent=indent) # type: ignore + if PYDANTIC_V1: + return model.json(indent=indent) # type: ignore + return model.model_dump_json(indent=indent) + + +class _ModelDumpKwargs(TypedDict, total=False): + by_alias: bool def model_dump( model: pydantic.BaseModel, *, + exclude: IncEx | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, + warnings: bool = True, + mode: Literal["json", "python"] = "python", + by_alias: bool | None = None, ) -> dict[str, Any]: - if PYDANTIC_V2: + if (not PYDANTIC_V1) or hasattr(model, "model_dump"): + kwargs: _ModelDumpKwargs = {} + if by_alias is not None: + kwargs["by_alias"] = by_alias return model.model_dump( + mode=mode, + exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, + # warnings are not supported in Pydantic v1 + warnings=True if PYDANTIC_V1 else warnings, + **kwargs, ) return cast( "dict[str, Any]", model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, + exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias) ), ) def model_parse(model: type[_ModelT], data: Any) -> _ModelT: - if PYDANTIC_V2: - return model.model_validate(data) - return model.parse_obj(data) # pyright: ignore[reportDeprecated] + if PYDANTIC_V1: + return model.parse_obj(data) # pyright: ignore[reportDeprecated] + return model.model_validate(data) # generic models if TYPE_CHECKING: - class GenericModel(pydantic.BaseModel): - ... + class GenericModel(pydantic.BaseModel): ... else: - if PYDANTIC_V2: + if PYDANTIC_V1: + import pydantic.generics + + class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... + else: # there no longer needs to be a distinction in v2 but # we still have to create our own subclass to avoid # inconsistent MRO ordering errors - class GenericModel(pydantic.BaseModel): - ... - - else: - import pydantic.generics - - class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): - ... + class GenericModel(pydantic.BaseModel): ... # cached properties @@ -193,30 +205,22 @@ class typed_cached_property(Generic[_T]): func: Callable[[Any], _T] attrname: str | None - def __init__(self, func: Callable[[Any], _T]) -> None: - ... + def __init__(self, func: Callable[[Any], _T]) -> None: ... @overload - def __get__(self, instance: None, owner: type[Any] | None = None) -> Self: - ... + def __get__(self, instance: None, owner: type[Any] | None = None) -> Self: ... @overload - def __get__(self, instance: object, owner: type[Any] | None = None) -> _T: - ... + def __get__(self, instance: object, owner: type[Any] | None = None) -> _T: ... def __get__(self, instance: object, owner: type[Any] | None = None) -> _T | Self: raise NotImplementedError() - def __set_name__(self, owner: type[Any], name: str) -> None: - ... + 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: - ... + 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/_constants.py b/src/orb/_constants.py index 1d56f7fd..6ddf2c71 100644 --- a/src/orb/_constants.py +++ b/src/orb/_constants.py @@ -6,9 +6,9 @@ OVERRIDE_CAST_TO_HEADER = "____stainless_override_cast_to" # default timeout is 1 minute -DEFAULT_TIMEOUT = httpx.Timeout(timeout=60.0, connect=5.0) +DEFAULT_TIMEOUT = httpx.Timeout(timeout=60, connect=5.0) DEFAULT_MAX_RETRIES = 2 -DEFAULT_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20) +DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20) INITIAL_RETRY_DELAY = 0.5 MAX_RETRY_DELAY = 8.0 diff --git a/src/orb/_files.py b/src/orb/_files.py index 0d2022ae..76da9e08 100644 --- a/src/orb/_files.py +++ b/src/orb/_files.py @@ -3,8 +3,8 @@ import io import os import pathlib -from typing import overload -from typing_extensions import TypeGuard +from typing import Sequence, cast, overload +from typing_extensions import TypeVar, TypeGuard import anyio @@ -17,7 +17,9 @@ HttpxFileContent, HttpxRequestFiles, ) -from ._utils import is_tuple_t, is_mapping_t, is_sequence_t +from ._utils import is_list, is_mapping, is_tuple_t, is_mapping_t, is_sequence_t + +_T = TypeVar("_T") def is_base64_file_input(obj: object) -> TypeGuard[Base64FileInput]: @@ -39,13 +41,11 @@ def assert_is_file_content(obj: object, *, key: str | None = None) -> None: @overload -def to_httpx_files(files: None) -> None: - ... +def to_httpx_files(files: None) -> None: ... @overload -def to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: - ... +def to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ... def to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None: @@ -71,25 +71,23 @@ def _transform_file(file: FileTypes) -> HttpxFileTypes: return file if is_tuple_t(file): - return (file[0], _read_file_content(file[1]), *file[2:]) + return (file[0], read_file_content(file[1]), *file[2:]) raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") -def _read_file_content(file: FileContent) -> HttpxFileContent: +def read_file_content(file: FileContent) -> HttpxFileContent: if isinstance(file, os.PathLike): return pathlib.Path(file).read_bytes() return file @overload -async def async_to_httpx_files(files: None) -> None: - ... +async def async_to_httpx_files(files: None) -> None: ... @overload -async def async_to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: - ... +async def async_to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ... async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None: @@ -101,7 +99,7 @@ async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles elif is_sequence_t(files): files = [(key, await _async_transform_file(file)) for key, file in files] else: - raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence") + raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence") return files @@ -115,13 +113,61 @@ async def _async_transform_file(file: FileTypes) -> HttpxFileTypes: return file if is_tuple_t(file): - return (file[0], await _async_read_file_content(file[1]), *file[2:]) + return (file[0], await async_read_file_content(file[1]), *file[2:]) raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") -async def _async_read_file_content(file: FileContent) -> HttpxFileContent: +async def async_read_file_content(file: FileContent) -> HttpxFileContent: if isinstance(file, os.PathLike): return await anyio.Path(file).read_bytes() return file + + +def deepcopy_with_paths(item: _T, paths: Sequence[Sequence[str]]) -> _T: + """Copy only the containers along the given paths. + + Used to guard against mutation by extract_files without copying the entire structure. + Only dicts and lists that lie on a path are copied; everything else + is returned by reference. + + For example, given paths=[["foo", "files", "file"]] and the structure: + { + "foo": { + "bar": {"baz": {}}, + "files": {"file": } + } + } + The root dict, "foo", and "files" are copied (they lie on the path). + "bar" and "baz" are returned by reference (off the path). + """ + return _deepcopy_with_paths(item, paths, 0) + + +def _deepcopy_with_paths(item: _T, paths: Sequence[Sequence[str]], index: int) -> _T: + if not paths: + return item + if is_mapping(item): + key_to_paths: dict[str, list[Sequence[str]]] = {} + for path in paths: + if index < len(path): + key_to_paths.setdefault(path[index], []).append(path) + + # if no path continues through this mapping, it won't be mutated and copying it is redundant + if not key_to_paths: + return item + + result = dict(item) + for key, subpaths in key_to_paths.items(): + if key in result: + result[key] = _deepcopy_with_paths(result[key], subpaths, index + 1) + return cast(_T, result) + if is_list(item): + array_paths = [path for path in paths if index < len(path) and path[index] == ""] + + # if no path expects a list here, nothing will be mutated inside it - return by reference + if not array_paths: + return cast(_T, item) + return cast(_T, [_deepcopy_with_paths(entry, array_paths, index + 1) for entry in item]) + return item diff --git a/src/orb/_legacy_response.py b/src/orb/_legacy_response.py index 6fb2d7fd..a78dda22 100644 --- a/src/orb/_legacy_response.py +++ b/src/orb/_legacy_response.py @@ -5,7 +5,18 @@ import logging import datetime import functools -from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, Iterator, AsyncIterator, cast, overload +from typing import ( + TYPE_CHECKING, + Any, + Union, + Generic, + TypeVar, + Callable, + Iterator, + AsyncIterator, + cast, + overload, +) from typing_extensions import Awaitable, ParamSpec, override, deprecated, get_origin import anyio @@ -13,7 +24,7 @@ import pydantic from ._types import NoneType -from ._utils import is_given, extract_type_arg, is_annotated_type +from ._utils import is_given, extract_type_arg, is_annotated_type, is_type_alias_type from ._models import BaseModel, is_basemodel from ._constants import RAW_RESPONSE_HEADER from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type @@ -53,6 +64,9 @@ class LegacyAPIResponse(Generic[R]): http_response: httpx.Response + retries_taken: int + """The number of retries made. If no retries happened this will be `0`""" + def __init__( self, *, @@ -62,6 +76,7 @@ def __init__( stream: bool, stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, options: FinalRequestOptions, + retries_taken: int = 0, ) -> None: self._cast_to = cast_to self._client = client @@ -70,14 +85,13 @@ def __init__( self._stream_cls = stream_cls self._options = options self.http_response = raw + self.retries_taken = retries_taken @overload - def parse(self, *, to: type[_T]) -> _T: - ... + def parse(self, *, to: type[_T]) -> _T: ... @overload - def parse(self) -> R: - ... + def parse(self) -> R: ... def parse(self, *, to: type[_T] | None = None) -> R | _T: """Returns the rich python representation of this response's data. @@ -174,9 +188,17 @@ def elapsed(self) -> datetime.timedelta: return self.http_response.elapsed def _parse(self, *, to: type[_T] | None = None) -> R | _T: + cast_to = to if to is not None else self._cast_to + + # unwrap `TypeAlias('Name', T)` -> `T` + if is_type_alias_type(cast_to): + cast_to = cast_to.__value__ # type: ignore[unreachable] + # unwrap `Annotated[T, ...]` -> `T` - if to and is_annotated_type(to): - to = extract_type_arg(to, 0) + if cast_to and is_annotated_type(cast_to): + cast_to = extract_type_arg(cast_to, 0) + + origin = get_origin(cast_to) or cast_to if self._stream: if to: @@ -192,6 +214,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: ), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -202,6 +225,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: cast_to=extract_stream_chunk_type(self._stream_cls), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -212,18 +236,13 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: return cast( R, stream_cls( - cast_to=self._cast_to, + cast_to=cast_to, response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) - cast_to = to if to is not None else self._cast_to - - # unwrap `Annotated[T, ...]` -> `T` - if is_annotated_type(cast_to): - cast_to = extract_type_arg(cast_to, 0) - if cast_to is NoneType: return cast(R, None) @@ -237,7 +256,8 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: if cast_to == float: return cast(R, float(response.text)) - origin = get_origin(cast_to) or cast_to + if cast_to == bool: + return cast(R, response.text.lower() == "true") if inspect.isclass(origin) and issubclass(origin, HttpxBinaryResponseContent): return cast(R, cast_to(response)) # type: ignore @@ -245,7 +265,9 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: if origin == LegacyAPIResponse: raise RuntimeError("Unexpected state - cast_to is `APIResponse`") - if inspect.isclass(origin) and issubclass(origin, httpx.Response): + if inspect.isclass( + origin # pyright: ignore[reportUnknownArgumentType] + ) and issubclass(origin, httpx.Response): # Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response # and pass that class to our request functions. We cannot change the variance to be either # covariant or contravariant as that makes our usage of ResponseT illegal. We could construct @@ -255,7 +277,13 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`") return cast(R, response) - if inspect.isclass(origin) and not issubclass(origin, BaseModel) and issubclass(origin, pydantic.BaseModel): + if ( + inspect.isclass( + origin # pyright: ignore[reportUnknownArgumentType] + ) + and not issubclass(origin, BaseModel) + and issubclass(origin, pydantic.BaseModel) + ): raise TypeError("Pydantic models must subclass our base model type, e.g. `from orb import BaseModel`") if ( @@ -272,7 +300,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: # split is required to handle cases where additional information is included # in the response, e.g. application/json; charset=utf-8 content_type, *_ = response.headers.get("content-type", "*").split(";") - if content_type != "application/json": + if not content_type.endswith("json"): if is_basemodel(cast_to): try: data = response.json() diff --git a/src/orb/_models.py b/src/orb/_models.py index 77c755b1..8c5ab260 100644 --- a/src/orb/_models.py +++ b/src/orb/_models.py @@ -1,15 +1,33 @@ from __future__ import annotations +import os import inspect -from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, cast +import weakref +from typing import ( + IO, + TYPE_CHECKING, + Any, + Type, + Union, + Generic, + TypeVar, + Callable, + Iterable, + Optional, + AsyncIterable, + cast, +) from datetime import date, datetime -from functools import lru_cache from typing_extensions import ( + List, Unpack, Literal, ClassVar, Protocol, Required, + Annotated, + ParamSpec, + TypeAlias, TypedDict, TypeGuard, final, @@ -18,7 +36,6 @@ ) import pydantic -import pydantic.generics from pydantic.fields import FieldInfo from ._types import ( @@ -36,16 +53,20 @@ PropertyInfo, is_list, is_given, + json_safe, + lru_cache, is_mapping, parse_date, + coerce_boolean, parse_datetime, strip_not_given, extract_type_arg, is_annotated_type, + is_type_alias_type, strip_annotated_type, ) from ._compat import ( - PYDANTIC_V2, + PYDANTIC_V1, ConfigDict, GenericModel as BaseGenericModel, get_args, @@ -60,11 +81,22 @@ from ._constants import RAW_RESPONSE_HEADER if TYPE_CHECKING: - from pydantic_core.core_schema import ModelField, ModelFieldsSchema + from pydantic import GetCoreSchemaHandler, ValidatorFunctionWrapHandler + from pydantic_core import CoreSchema, core_schema + from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema +else: + try: + from pydantic_core import CoreSchema, core_schema + except ImportError: + CoreSchema = None + core_schema = None __all__ = ["BaseModel", "GenericModel"] _T = TypeVar("_T") +_BaseModelT = TypeVar("_BaseModelT", bound="BaseModel") + +P = ParamSpec("P") @runtime_checkable @@ -73,9 +105,7 @@ class _ConfigProtocol(Protocol): class BaseModel(pydantic.BaseModel): - if PYDANTIC_V2: - model_config: ClassVar[ConfigDict] = ConfigDict(extra="allow") - else: + if PYDANTIC_V1: @property @override @@ -85,25 +115,102 @@ def model_fields_set(self) -> set[str]: class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] extra: Any = pydantic.Extra.allow # type: ignore + else: + model_config: ClassVar[ConfigDict] = ConfigDict( + extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) + ) + + def to_dict( + self, + *, + mode: Literal["json", "python"] = "python", + use_api_names: bool = True, + exclude_unset: bool = True, + exclude_defaults: bool = False, + exclude_none: bool = False, + warnings: bool = True, + ) -> dict[str, object]: + """Recursively generate a dictionary representation of the model, optionally specifying which fields to include or exclude. + + By default, fields that were not set by the API will not be included, + and keys will match the API response, *not* the property names from the model. + + For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property, + the output will use the `"fooBar"` key (unless `use_api_names=False` is passed). + + Args: + mode: + If mode is 'json', the dictionary will only contain JSON serializable types. e.g. `datetime` will be turned into a string, `"2024-3-22T18:11:19.117000Z"`. + If mode is 'python', the dictionary may contain any Python objects. e.g. `datetime(2024, 3, 22)` + + use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value from the output. + exclude_none: Whether to exclude fields that have a value of `None` from the output. + warnings: Whether to log warnings when invalid fields are encountered. This is only supported in Pydantic v2. + """ + return self.model_dump( + mode=mode, + by_alias=use_api_names, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + warnings=warnings, + ) + + def to_json( + self, + *, + indent: int | None = 2, + use_api_names: bool = True, + exclude_unset: bool = True, + exclude_defaults: bool = False, + exclude_none: bool = False, + warnings: bool = True, + ) -> str: + """Generates a JSON string representing this model as it would be received from or sent to the API (but with indentation). + + By default, fields that were not set by the API will not be included, + and keys will match the API response, *not* the property names from the model. + + For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property, + the output will use the `"fooBar"` key (unless `use_api_names=False` is passed). + + Args: + indent: Indentation to use in the JSON output. If `None` is passed, the output will be compact. Defaults to `2` + use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that have the default value. + exclude_none: Whether to exclude fields that have a value of `None`. + warnings: Whether to show any warnings that occurred during serialization. This is only supported in Pydantic v2. + """ + return self.model_dump_json( + indent=indent, + by_alias=use_api_names, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + warnings=warnings, + ) @override def __str__(self) -> str: # mypy complains about an invalid self arg - return f'{self.__repr_name__()}({self.__repr_str__(", ")})' # type: ignore[misc] + return f"{self.__repr_name__()}({self.__repr_str__(', ')})" # type: ignore[misc] # Override the 'construct' method in a way that supports recursive parsing without validation. # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836. @classmethod @override - def construct( - cls: Type[ModelT], + def construct( # pyright: ignore[reportIncompatibleMethodOverride] + __cls: Type[ModelT], _fields_set: set[str] | None = None, **values: object, ) -> ModelT: - m = cls.__new__(cls) + m = __cls.__new__(__cls) fields_values: dict[str, object] = {} - config = get_model_config(cls) + config = get_model_config(__cls) populate_by_name = ( config.allow_population_by_field_name if isinstance(config, _ConfigProtocol) @@ -113,7 +220,7 @@ def construct( if _fields_set is None: _fields_set = set() - model_fields = get_model_fields(cls) + model_fields = get_model_fields(__cls) for name, field in model_fields.items(): key = field.alias if key is None or (key not in values and populate_by_name): @@ -125,28 +232,32 @@ def construct( else: fields_values[name] = field_get_default(field) + extra_field_type = _get_extra_fields_type(__cls) + _extra = {} for key, value in values.items(): if key not in model_fields: - if PYDANTIC_V2: - _extra[key] = value - else: + parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value + + if PYDANTIC_V1: _fields_set.add(key) - fields_values[key] = value + fields_values[key] = parsed + else: + _extra[key] = parsed object.__setattr__(m, "__dict__", fields_values) - if PYDANTIC_V2: - # these properties are copied from Pydantic's `model_construct()` method - object.__setattr__(m, "__pydantic_private__", None) - object.__setattr__(m, "__pydantic_extra__", _extra) - object.__setattr__(m, "__pydantic_fields_set__", _fields_set) - else: + if PYDANTIC_V1: # init_private_attributes() does not exist in v2 m._init_private_attributes() # type: ignore # copied from Pydantic v1's `construct()` method object.__setattr__(m, "__fields_set__", _fields_set) + else: + # these properties are copied from Pydantic's `model_construct()` method + object.__setattr__(m, "__pydantic_private__", None) + object.__setattr__(m, "__pydantic_extra__", _extra) + object.__setattr__(m, "__pydantic_fields_set__", _fields_set) return m @@ -156,7 +267,7 @@ def construct( # although not in practice model_construct = construct - if not PYDANTIC_V2: + if PYDANTIC_V1: # we define aliases for some of the new pydantic v2 methods so # that we can just document these methods without having to specify # a specific pydantic version as some users may not know which @@ -167,14 +278,18 @@ def model_dump( self, *, mode: Literal["json", "python"] | str = "python", - include: IncEx = None, - exclude: IncEx = None, - by_alias: bool = False, + include: IncEx | None = None, + exclude: IncEx | None = None, + context: Any | None = None, + by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, + exclude_computed_fields: bool = False, round_trip: bool = False, - warnings: bool = True, + warnings: bool | Literal["none", "warn", "error"] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, ) -> dict[str, Any]: """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump @@ -182,48 +297,71 @@ def model_dump( Args: mode: The mode in which `to_python` should run. - If mode is 'json', the dictionary will only contain JSON serializable types. - If mode is 'python', the dictionary may contain any Python objects. - include: A list of fields to include in the output. - exclude: A list of fields to exclude from the output. + If mode is 'json', the output will only contain JSON serializable types. + If mode is 'python', the output may contain non-JSON-serializable Python objects. + include: A set of fields to include in the output. + exclude: A set of fields to exclude from the output. + context: Additional context to pass to the serializer. by_alias: Whether to use the field's alias in the dictionary key if defined. - exclude_unset: Whether to exclude fields that are unset or None from the output. - exclude_defaults: Whether to exclude fields that are set to their default value from the output. - exclude_none: Whether to exclude fields that have a value of `None` from the output. - round_trip: Whether to enable serialization and deserialization round-trip support. - warnings: Whether to log warnings when invalid fields are encountered. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value. + exclude_none: Whether to exclude fields that have a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T]. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. 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: raise ValueError("warnings is only supported in Pydantic v2") - return super().dict( # pyright: ignore[reportDeprecated] + if context is not None: + 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") + if fallback is not None: + raise ValueError("fallback is only supported in Pydantic v2") + if exclude_computed_fields != False: + raise ValueError("exclude_computed_fields is only supported in Pydantic v2") + dumped = super().dict( # pyright: ignore[reportDeprecated] include=include, exclude=exclude, - by_alias=by_alias, + by_alias=by_alias if by_alias is not None else False, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, 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, - by_alias: bool = False, + ensure_ascii: bool = False, + include: IncEx | None = None, + exclude: IncEx | None = None, + context: Any | None = None, + by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, + exclude_computed_fields: bool = False, round_trip: bool = False, - warnings: bool = True, + warnings: bool | Literal["none", "warn", "error"] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, ) -> str: """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json @@ -247,30 +385,127 @@ def model_dump_json( raise ValueError("round_trip is only supported in Pydantic v2") if warnings != True: raise ValueError("warnings is only supported in Pydantic v2") + if context is not None: + 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") + if fallback is not None: + raise ValueError("fallback is only supported in Pydantic v2") + if ensure_ascii != False: + raise ValueError("ensure_ascii is only supported in Pydantic v2") + if exclude_computed_fields != False: + raise ValueError("exclude_computed_fields is only supported in Pydantic v2") return super().json( # type: ignore[reportDeprecated] indent=indent, include=include, exclude=exclude, - by_alias=by_alias, + by_alias=by_alias if by_alias is not None else False, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, exclude_none=exclude_none, ) +class _EagerIterable(list[_T], Generic[_T]): + """ + Accepts any Iterable[T] input (including generators), consumes it + eagerly, and validates all items upfront. + + Validation preserves the original container type where possible + (e.g. a set[T] stays a set[T]). Serialization (model_dump / JSON) + always emits a list — round-tripping through model_dump() will not + restore the original container type. + """ + + @classmethod + def __get_pydantic_core_schema__( + cls, + source_type: Any, + handler: GetCoreSchemaHandler, + ) -> CoreSchema: + (item_type,) = get_args(source_type) or (Any,) + item_schema: CoreSchema = handler.generate_schema(item_type) + list_of_items_schema: CoreSchema = core_schema.list_schema(item_schema) + + return core_schema.no_info_wrap_validator_function( + cls._validate, + list_of_items_schema, + serialization=core_schema.plain_serializer_function_ser_schema( + cls._serialize, + info_arg=False, + ), + ) + + @staticmethod + def _validate(v: Iterable[_T], handler: "ValidatorFunctionWrapHandler") -> Any: + original_type: type[Any] = type(v) + + # Normalize to list so list_schema can validate each item + if isinstance(v, list): + items: list[_T] = v + else: + try: + items = list(v) + except TypeError as e: + raise TypeError("Value is not iterable") from e + + # Validate items against the inner schema + validated: list[_T] = handler(items) + + # Reconstruct original container type + if original_type is list: + return validated + # str(list) produces the list's repr, not a string built from items, + # so skip reconstruction for str and its subclasses. + if issubclass(original_type, str): + return validated + try: + return original_type(validated) + except (TypeError, ValueError): + # If the type cannot be reconstructed, just return the validated list + return validated + + @staticmethod + def _serialize(v: Iterable[_T]) -> list[_T]: + """Always serialize as a list so Pydantic's JSON encoder is happy.""" + if isinstance(v, list): + return v + return list(v) + + +EagerIterable: TypeAlias = Annotated[Iterable[_T], _EagerIterable] + + def _construct_field(value: object, field: FieldInfo, key: str) -> object: if value is None: return field_get_default(field) - if PYDANTIC_V2: - type_ = field.annotation - else: + if PYDANTIC_V1: type_ = cast(type, field.outer_type_) # type: ignore + else: + type_ = field.annotation # type: ignore if type_ is None: raise RuntimeError(f"Unexpected field type is None for {key}") - return construct_type(value=value, type_=type_) + return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None)) + + +def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None: + if PYDANTIC_V1: + # TODO + return None + + schema = cls.__pydantic_core_schema__ + if schema["type"] == "model": + fields = schema["schema"] + if fields["type"] == "model-fields": + extras = fields.get("extras_schema") + if extras and "cls" in extras: + # mypy can't narrow the type + return extras["cls"] # type: ignore[no-any-return] + + return None def is_basemodel(type_: type) -> bool: @@ -287,20 +522,64 @@ def is_basemodel(type_: type) -> bool: def is_basemodel_type(type_: type) -> TypeGuard[type[BaseModel] | type[GenericModel]]: origin = get_origin(type_) or type_ + if not inspect.isclass(origin): + return False return issubclass(origin, BaseModel) or issubclass(origin, GenericModel) -def construct_type(*, value: object, type_: object) -> object: +def build( + base_model_cls: Callable[P, _BaseModelT], + *args: P.args, + **kwargs: P.kwargs, +) -> _BaseModelT: + """Construct a BaseModel class without validation. + + This is useful for cases where you need to instantiate a `BaseModel` + from an API response as this provides type-safe params which isn't supported + by helpers like `construct_type()`. + + ```py + build(MyModel, my_field_a="foo", my_field_b=123) + ``` + """ + if args: + raise TypeError( + "Received positional arguments which are not supported; Keyword arguments must be used instead", + ) + + return cast(_BaseModelT, construct_type(type_=base_model_cls, value=kwargs)) + + +def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T: + """Loose coercion to the expected type with construction of nested values. + + Note: the returned value from this function is not guaranteed to match the + given type. + """ + return cast(_T, construct_type(value=value, type_=type_)) + + +def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]] = None) -> object: """Loose coercion to the expected type with construction of nested values. If the given value does not match the expected type then it is returned as-is. """ + + # store a reference to the original type we were given before we extract any inner + # types so that we can properly resolve forward references in `TypeAliasType` annotations + original_type = None + # we allow `object` as the input type because otherwise, passing things like # `Literal['value']` will be reported as a type error by type checkers type_ = cast("type[object]", type_) + if is_type_alias_type(type_): + original_type = type_ # type: ignore[unreachable] + type_ = type_.__value__ # type: ignore[unreachable] # unwrap `Annotated[T, ...]` -> `T` - if is_annotated_type(type_): + if metadata is not None and len(metadata) > 0: + meta: tuple[Any, ...] = tuple(metadata) + elif is_annotated_type(type_): meta = get_args(type_)[1:] type_ = extract_type_arg(type_, 0) else: @@ -313,7 +592,7 @@ def construct_type(*, value: object, type_: object) -> object: if is_union(origin): try: - return validate_type(type_=cast("type[object]", type_), value=value) + return validate_type(type_=cast("type[object]", original_type or type_), value=value) except Exception: pass @@ -355,7 +634,11 @@ def construct_type(*, value: object, type_: object) -> object: _, items_type = get_args(type_) # Dict[_, items_type] return {key: construct_type(value=item, type_=items_type) for key, item in value.items()} - if not is_literal_type(type_) and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel)): + if ( + not is_literal_type(type_) + and inspect.isclass(origin) + and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel)) + ): if is_list(value): return [cast(Any, type_).construct(**entry) if is_mapping(entry) else entry for entry in value] @@ -401,6 +684,9 @@ class CachedDiscriminatorType(Protocol): __discriminator__: DiscriminatorDetails +DISCRIMINATOR_CACHE: weakref.WeakKeyDictionary[type, DiscriminatorDetails] = weakref.WeakKeyDictionary() + + class DiscriminatorDetails: field_name: str """The name of the discriminator field in the variant class, e.g. @@ -443,8 +729,9 @@ def __init__( def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None: - if isinstance(union, CachedDiscriminatorType): - return union.__discriminator__ + cached = DISCRIMINATOR_CACHE.get(union) + if cached is not None: + return cached discriminator_field_name: str | None = None @@ -462,30 +749,30 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, for variant in get_args(union): variant = strip_annotated_type(variant) if is_basemodel_type(variant): - if PYDANTIC_V2: - field = _extract_field_schema_pv2(variant, discriminator_field_name) - if not field: + if PYDANTIC_V1: + field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + if not field_info: continue # Note: if one variant defines an alias then they all should - discriminator_alias = field.get("serialization_alias") - - field_schema = field["schema"] + discriminator_alias = field_info.alias - if field_schema["type"] == "literal": - for entry in field_schema["expected"]: + if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): + for entry in get_args(annotation): if isinstance(entry, str): mapping[entry] = variant else: - field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - if not field_info: + field = _extract_field_schema_pv2(variant, discriminator_field_name) + if not field: continue # Note: if one variant defines an alias then they all should - discriminator_alias = field_info.alias + discriminator_alias = field.get("serialization_alias") - if field_info.annotation and is_literal_type(field_info.annotation): - for entry in get_args(field_info.annotation): + field_schema = field["schema"] + + if field_schema["type"] == "literal": + for entry in cast("LiteralSchema", field_schema)["expected"]: if isinstance(entry, str): mapping[entry] = variant @@ -497,21 +784,24 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, discriminator_field=discriminator_field_name, discriminator_alias=discriminator_alias, ) - cast(CachedDiscriminatorType, union).__discriminator__ = details + DISCRIMINATOR_CACHE.setdefault(union, details) return details def _extract_field_schema_pv2(model: type[BaseModel], field_name: str) -> ModelField | None: schema = model.__pydantic_core_schema__ + if schema["type"] == "definitions": + schema = schema["schema"] + if schema["type"] != "model": return None + schema = cast("ModelSchema", schema) fields_schema = schema["schema"] if fields_schema["type"] != "model-fields": return None fields_schema = cast("ModelFieldsSchema", fields_schema) - field = fields_schema["fields"].get(field_name) if not field: return None @@ -527,7 +817,15 @@ def validate_type(*, type_: type[_T], value: object) -> _T: return cast(_T, _validate_non_model_type(type_=type_, value=value)) -# our use of subclasssing here causes weirdness for type checkers, +def set_pydantic_config(typ: Any, config: pydantic.ConfigDict) -> None: + """Add a pydantic config for the given type. + + Note: this is a no-op on Pydantic v1. + """ + setattr(typ, "__pydantic_config__", config) # noqa: B010 + + +# our use of subclassing here causes weirdness for type checkers, # so we just pretend that we don't subclass if TYPE_CHECKING: GenericModel = BaseModel @@ -537,7 +835,7 @@ class GenericModel(BaseGenericModel, BaseModel): pass -if PYDANTIC_V2: +if not PYDANTIC_V1: from pydantic import TypeAdapter as _TypeAdapter _CachedTypeAdapter = cast("TypeAdapter[object]", lru_cache(maxsize=None)(_TypeAdapter)) @@ -582,8 +880,10 @@ class FinalRequestOptionsInput(TypedDict, total=False): timeout: float | Timeout | None files: HttpxRequestFiles | None idempotency_key: str + content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] json_data: Body extra_json: AnyMapping + follow_redirects: bool @final @@ -597,18 +897,20 @@ class FinalRequestOptions(pydantic.BaseModel): files: Union[HttpxRequestFiles, None] = None idempotency_key: Union[str, None] = None post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() + follow_redirects: Union[bool, None] = None + content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] = None # It should be noted that we cannot use `json` here as that would override # a BaseModel method in an incompatible fashion. json_data: Union[Body, None] = None extra_json: Union[AnyMapping, None] = None - if PYDANTIC_V2: - model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) - else: + if PYDANTIC_V1: class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] arbitrary_types_allowed: bool = True + else: + model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) def get_max_retries(self, max_retries: int) -> int: if isinstance(self.max_retries, NotGiven): @@ -641,9 +943,9 @@ def construct( # type: ignore key: strip_not_given(value) for key, value in values.items() } - if PYDANTIC_V2: - return super().model_construct(_fields_set, **kwargs) - return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] + if PYDANTIC_V1: + return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] + return super().model_construct(_fields_set, **kwargs) if not TYPE_CHECKING: # type checkers incorrectly complain about this assignment diff --git a/src/orb/_qs.py b/src/orb/_qs.py index 274320ca..4127c19c 100644 --- a/src/orb/_qs.py +++ b/src/orb/_qs.py @@ -2,17 +2,13 @@ from typing import Any, List, Tuple, Union, Mapping, TypeVar from urllib.parse import parse_qs, urlencode -from typing_extensions import Literal, get_args +from typing_extensions import get_args -from ._types import NOT_GIVEN, NotGiven, NotGivenOr +from ._types import NotGiven, ArrayFormat, NestedFormat, not_given from ._utils import flatten _T = TypeVar("_T") - -ArrayFormat = Literal["comma", "repeat", "indices", "brackets"] -NestedFormat = Literal["dots", "brackets"] - PrimitiveData = Union[str, int, float, bool, None] # this should be Data = Union[PrimitiveData, "List[Data]", "Tuple[Data]", "Mapping[str, Data]"] # https://github.com/microsoft/pyright/issues/3555 @@ -41,8 +37,8 @@ def stringify( self, params: Params, *, - array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, - nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, ) -> str: return urlencode( self.stringify_items( @@ -56,8 +52,8 @@ def stringify_items( self, params: Params, *, - array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, - nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, ) -> list[tuple[str, str]]: opts = Options( qs=self, @@ -101,7 +97,10 @@ def _stringify_item( items.extend(self._stringify_item(key, item, opts)) return items elif array_format == "indices": - raise NotImplementedError("The array indices format is not supported yet") + items = [] + for i, item in enumerate(value): + items.extend(self._stringify_item(f"{key}[{i}]", item, opts)) + return items elif array_format == "brackets": items = [] key = key + "[]" @@ -143,8 +142,8 @@ def __init__( self, qs: Querystring = _qs, *, - array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, - nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, ) -> None: self.array_format = qs.array_format if isinstance(array_format, NotGiven) else array_format self.nested_format = qs.nested_format if isinstance(nested_format, NotGiven) else nested_format diff --git a/src/orb/_response.py b/src/orb/_response.py index a3332803..d8a81963 100644 --- a/src/orb/_response.py +++ b/src/orb/_response.py @@ -25,7 +25,7 @@ import pydantic from ._types import NoneType -from ._utils import is_given, extract_type_arg, is_annotated_type, extract_type_var_from_base +from ._utils import is_given, extract_type_arg, is_annotated_type, is_type_alias_type, extract_type_var_from_base from ._models import BaseModel, is_basemodel from ._constants import RAW_RESPONSE_HEADER, OVERRIDE_CAST_TO_HEADER from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type @@ -55,6 +55,9 @@ class BaseAPIResponse(Generic[R]): http_response: httpx.Response + retries_taken: int + """The number of retries made. If no retries happened this will be `0`""" + def __init__( self, *, @@ -64,6 +67,7 @@ def __init__( stream: bool, stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, options: FinalRequestOptions, + retries_taken: int = 0, ) -> None: self._cast_to = cast_to self._client = client @@ -72,6 +76,7 @@ def __init__( self._stream_cls = stream_cls self._options = options self.http_response = raw + self.retries_taken = retries_taken @property def headers(self) -> httpx.Headers: @@ -121,9 +126,17 @@ def __repr__(self) -> str: ) def _parse(self, *, to: type[_T] | None = None) -> R | _T: + cast_to = to if to is not None else self._cast_to + + # unwrap `TypeAlias('Name', T)` -> `T` + if is_type_alias_type(cast_to): + cast_to = cast_to.__value__ # type: ignore[unreachable] + # unwrap `Annotated[T, ...]` -> `T` - if to and is_annotated_type(to): - to = extract_type_arg(to, 0) + if cast_to and is_annotated_type(cast_to): + cast_to = extract_type_arg(cast_to, 0) + + origin = get_origin(cast_to) or cast_to if self._is_sse_stream: if to: @@ -139,6 +152,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: ), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -149,6 +163,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: cast_to=extract_stream_chunk_type(self._stream_cls), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -159,18 +174,13 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: return cast( R, stream_cls( - cast_to=self._cast_to, + cast_to=cast_to, response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) - cast_to = to if to is not None else self._cast_to - - # unwrap `Annotated[T, ...]` -> `T` - if is_annotated_type(cast_to): - cast_to = extract_type_arg(cast_to, 0) - if cast_to is NoneType: return cast(R, None) @@ -187,7 +197,8 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: if cast_to == float: return cast(R, float(response.text)) - origin = get_origin(cast_to) or cast_to + if cast_to == bool: + return cast(R, response.text.lower() == "true") # handle the legacy binary response case if inspect.isclass(cast_to) and cast_to.__name__ == "HttpxBinaryResponseContent": @@ -206,7 +217,13 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`") return cast(R, response) - if inspect.isclass(origin) and not issubclass(origin, BaseModel) and issubclass(origin, pydantic.BaseModel): + if ( + inspect.isclass( + origin # pyright: ignore[reportUnknownArgumentType] + ) + and not issubclass(origin, BaseModel) + and issubclass(origin, pydantic.BaseModel) + ): raise TypeError("Pydantic models must subclass our base model type, e.g. `from orb import BaseModel`") if ( @@ -223,7 +240,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: # split is required to handle cases where additional information is included # in the response, e.g. application/json; charset=utf-8 content_type, *_ = response.headers.get("content-type", "*").split(";") - if content_type != "application/json": + if not content_type.endswith("json"): if is_basemodel(cast_to): try: data = response.json() @@ -259,12 +276,10 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: class APIResponse(BaseAPIResponse[R]): @overload - def parse(self, *, to: type[_T]) -> _T: - ... + def parse(self, *, to: type[_T]) -> _T: ... @overload - def parse(self) -> R: - ... + def parse(self) -> R: ... def parse(self, *, to: type[_T] | None = None) -> R | _T: """Returns the rich python representation of this response's data. @@ -363,12 +378,10 @@ def iter_lines(self) -> Iterator[str]: class AsyncAPIResponse(BaseAPIResponse[R]): @overload - async def parse(self, *, to: type[_T]) -> _T: - ... + async def parse(self, *, to: type[_T]) -> _T: ... @overload - async def parse(self) -> R: - ... + async def parse(self) -> R: ... async def parse(self, *, to: type[_T] | None = None) -> R | _T: """Returns the rich python representation of this response's data. diff --git a/src/orb/_streaming.py b/src/orb/_streaming.py index d1d7d03f..321fe6aa 100644 --- a/src/orb/_streaming.py +++ b/src/orb/_streaming.py @@ -4,7 +4,7 @@ import json import inspect from types import TracebackType -from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, AsyncIterator, cast +from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, Optional, AsyncIterator, cast from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable import httpx @@ -13,6 +13,7 @@ if TYPE_CHECKING: from ._client import Orb, AsyncOrb + from ._models import FinalRequestOptions _T = TypeVar("_T") @@ -22,8 +23,8 @@ class Stream(Generic[_T]): """Provides the core interface to iterate over a synchronous stream response.""" response: httpx.Response - - _decoder: SSEDecoder | SSEBytesDecoder + _options: Optional[FinalRequestOptions] = None + _decoder: SSEBytesDecoder def __init__( self, @@ -31,10 +32,12 @@ def __init__( cast_to: type[_T], response: httpx.Response, client: Orb, + options: Optional[FinalRequestOptions] = None, ) -> None: self.response = response self._cast_to = cast_to self._client = client + self._options = options self._decoder = client._make_sse_decoder() self._iterator = self.__stream__() @@ -46,10 +49,7 @@ def __iter__(self) -> Iterator[_T]: yield item def _iter_events(self) -> Iterator[ServerSentEvent]: - if isinstance(self._decoder, SSEBytesDecoder): - yield from self._decoder.iter_bytes(self.response.iter_bytes()) - else: - yield from self._decoder.iter(self.response.iter_lines()) + yield from self._decoder.iter_bytes(self.response.iter_bytes()) def __stream__(self) -> Iterator[_T]: cast_to = cast(Any, self._cast_to) @@ -57,12 +57,12 @@ def __stream__(self) -> Iterator[_T]: process_data = self._client._process_response_data iterator = self._iter_events() - for sse in iterator: - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - - # Ensure the entire stream is consumed - for _sse in iterator: - ... + try: + for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + response.close() def __enter__(self) -> Self: return self @@ -88,7 +88,7 @@ class AsyncStream(Generic[_T]): """Provides the core interface to iterate over an asynchronous stream response.""" response: httpx.Response - + _options: Optional[FinalRequestOptions] = None _decoder: SSEDecoder | SSEBytesDecoder def __init__( @@ -97,10 +97,12 @@ def __init__( cast_to: type[_T], response: httpx.Response, client: AsyncOrb, + options: Optional[FinalRequestOptions] = None, ) -> None: self.response = response self._cast_to = cast_to self._client = client + self._options = options self._decoder = client._make_sse_decoder() self._iterator = self.__stream__() @@ -112,12 +114,8 @@ async def __aiter__(self) -> AsyncIterator[_T]: yield item async def _iter_events(self) -> AsyncIterator[ServerSentEvent]: - if isinstance(self._decoder, SSEBytesDecoder): - async for sse in self._decoder.aiter_bytes(self.response.aiter_bytes()): - yield sse - else: - async for sse in self._decoder.aiter(self.response.aiter_lines()): - yield sse + async for sse in self._decoder.aiter_bytes(self.response.aiter_bytes()): + yield sse async def __stream__(self) -> AsyncIterator[_T]: cast_to = cast(Any, self._cast_to) @@ -125,12 +123,12 @@ async def __stream__(self) -> AsyncIterator[_T]: process_data = self._client._process_response_data iterator = self._iter_events() - async for sse in iterator: - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - - # Ensure the entire stream is consumed - async for _sse in iterator: - ... + try: + async for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + await response.aclose() async def __aenter__(self) -> Self: return self @@ -205,21 +203,49 @@ def __init__(self) -> None: self._last_event_id = None self._retry = None - def iter(self, iterator: Iterator[str]) -> Iterator[ServerSentEvent]: - """Given an iterator that yields lines, iterate over it & yield every event encountered""" - for line in iterator: - line = line.rstrip("\n") - sse = self.decode(line) - if sse is not None: - yield sse - - async def aiter(self, iterator: AsyncIterator[str]) -> AsyncIterator[ServerSentEvent]: - """Given an async iterator that yields lines, iterate over it & yield every event encountered""" - async for line in iterator: - line = line.rstrip("\n") - sse = self.decode(line) - if sse is not None: - yield sse + def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]: + """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" + for chunk in self._iter_chunks(iterator): + # Split before decoding so splitlines() only uses \r and \n + for raw_line in chunk.splitlines(): + line = raw_line.decode("utf-8") + sse = self.decode(line) + if sse: + yield sse + + def _iter_chunks(self, iterator: Iterator[bytes]) -> Iterator[bytes]: + """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks""" + data = b"" + for chunk in iterator: + for line in chunk.splitlines(keepends=True): + data += line + if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")): + yield data + data = b"" + if data: + yield data + + async def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]: + """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" + async for chunk in self._aiter_chunks(iterator): + # Split before decoding so splitlines() only uses \r and \n + for raw_line in chunk.splitlines(): + line = raw_line.decode("utf-8") + sse = self.decode(line) + if sse: + yield sse + + async def _aiter_chunks(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[bytes]: + """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks""" + data = b"" + async for chunk in iterator: + for line in chunk.splitlines(keepends=True): + data += line + if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")): + yield data + data = b"" + if data: + yield data def decode(self, line: str) -> ServerSentEvent | None: # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501 diff --git a/src/orb/_types.py b/src/orb/_types.py index 4e90cff0..514f1d7a 100644 --- a/src/orb/_types.py +++ b/src/orb/_types.py @@ -13,10 +13,23 @@ Mapping, TypeVar, Callable, + Iterable, + Iterator, Optional, Sequence, + AsyncIterable, +) +from typing_extensions import ( + Set, + Literal, + Protocol, + TypeAlias, + TypedDict, + SupportsIndex, + overload, + override, + runtime_checkable, ) -from typing_extensions import Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable import httpx import pydantic @@ -35,6 +48,9 @@ ModelT = TypeVar("ModelT", bound=pydantic.BaseModel) _T = TypeVar("_T") +ArrayFormat = Literal["comma", "repeat", "indices", "brackets"] +NestedFormat = Literal["dots", "brackets"] + # Approximates httpx internal ProxiesTypes and RequestFiles types # while adding support for `PathLike` instances @@ -46,6 +62,13 @@ else: Base64FileInput = Union[IO[bytes], PathLike] FileContent = Union[IO[bytes], bytes, PathLike] # PathLike is not subscriptable in Python 3.8. + + +# Used for sending raw binary data / streaming data in request bodies +# e.g. for file uploads without multipart encoding +BinaryTypes = Union[bytes, bytearray, IO[bytes], Iterable[bytes]] +AsyncBinaryTypes = Union[bytes, bytearray, IO[bytes], AsyncIterable[bytes]] + FileTypes = Union[ # file (or bytes) FileContent, @@ -101,24 +124,27 @@ class RequestOptions(TypedDict, total=False): params: Query extra_json: AnyMapping idempotency_key: str + follow_redirects: bool # Sentinel class used until PEP 0661 is accepted class NotGiven: """ - A sentinel singleton class used to distinguish omitted keyword arguments - from those passed in with the value None (which may have different behavior). + For parameters with a meaningful None value, we need to distinguish between + the user explicitly passing None, and the user not passing the parameter at + all. + + User code shouldn't need to use not_given directly. For example: ```py - def get(timeout: Union[int, NotGiven, None] = NotGiven()) -> Response: - ... + def create(timeout: Timeout | None | NotGiven = not_given): ... - get(timeout=1) # 1s timeout - get(timeout=None) # No timeout - get() # Default timeout behavior, which may not be statically known at the method definition. + create(timeout=1) # 1s timeout + create(timeout=None) # No timeout + create() # Default timeout behavior ``` """ @@ -130,13 +156,14 @@ def __repr__(self) -> str: return "NOT_GIVEN" -NotGivenOr = Union[_T, NotGiven] +not_given = NotGiven() +# for backwards compatibility: NOT_GIVEN = NotGiven() class Omit: - """In certain situations you need to be able to represent a case where a default value has - to be explicitly removed and `None` is not an appropriate substitute, for example: + """ + To explicitly omit something from being sent in a request, use `omit`. ```py # as the default `Content-Type` header is `application/json` that will be sent @@ -146,8 +173,8 @@ class Omit: # to look something like: 'multipart/form-data; boundary=0d8382fcf5f8c3be01ca2e11002d2983' client.post(..., headers={"Content-Type": "multipart/form-data"}) - # instead you can remove the default `application/json` header by passing Omit - client.post(..., headers={"Content-Type": Omit()}) + # instead you can remove the default `application/json` header by passing omit + client.post(..., headers={"Content-Type": omit}) ``` """ @@ -155,6 +182,9 @@ def __bool__(self) -> Literal[False]: return False +omit = Omit() + + @runtime_checkable class ModelBuilderProtocol(Protocol): @classmethod @@ -163,16 +193,14 @@ def build( *, response: Response, data: object, - ) -> _T: - ... + ) -> _T: ... Headers = Mapping[str, Union[str, Omit]] class HeadersLikeProtocol(Protocol): - def get(self, __key: str) -> str | None: - ... + def get(self, __key: str) -> str | None: ... HeadersLike = Union[Headers, HeadersLikeProtocol] @@ -197,8 +225,8 @@ def get(self, __key: str) -> str | None: StrBytesIntFloat = Union[str, bytes, int, float] # 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" +# https://github.com/pydantic/pydantic/blob/6f31f8f68ef011f84357330186f603ff295312fd/pydantic/main.py#L79 +IncEx: TypeAlias = Union[Set[int], Set[str], Mapping[int, Union["IncEx", bool]], Mapping[str, Union["IncEx", bool]]] PostParser = Callable[[Any], Any] @@ -220,3 +248,28 @@ class _GenericAlias(Protocol): class HttpxSendArgs(TypedDict, total=False): auth: httpx.Auth + follow_redirects: bool + + +_T_co = TypeVar("_T_co", covariant=True) + + +if TYPE_CHECKING: + # This works because str.__contains__ does not accept object (either in typeshed or at runtime) + # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285 + # + # Note: index() and count() methods are intentionally omitted to allow pyright to properly + # infer TypedDict types when dict literals are used in lists assigned to SequenceNotStr. + class SequenceNotStr(Protocol[_T_co]): + @overload + def __getitem__(self, index: SupportsIndex, /) -> _T_co: ... + @overload + def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ... + def __contains__(self, value: object, /) -> bool: ... + def __len__(self) -> int: ... + def __iter__(self) -> Iterator[_T_co]: ... + def __reversed__(self) -> Iterator[_T_co]: ... +else: + # just point this to a normal `Sequence` at runtime to avoid having to special case + # deserializing our custom sequence type + SequenceNotStr = Sequence diff --git a/src/orb/_utils/__init__.py b/src/orb/_utils/__init__.py index 56978941..1c090e51 100644 --- a/src/orb/_utils/__init__.py +++ b/src/orb/_utils/__init__.py @@ -1,3 +1,4 @@ +from ._path import path_template as path_template from ._sync import asyncify as asyncify from ._proxy import LazyProxy as LazyProxy from ._utils import ( @@ -6,9 +7,10 @@ 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, - parse_date as parse_date, is_iterable as is_iterable, is_sequence as is_sequence, coerce_float as coerce_float, @@ -21,22 +23,29 @@ coerce_boolean as coerce_boolean, coerce_integer as coerce_integer, file_from_path as file_from_path, - parse_datetime as parse_datetime, strip_not_given as strip_not_given, - deepcopy_minimal as deepcopy_minimal, get_async_library as get_async_library, maybe_coerce_float as maybe_coerce_float, get_required_header as get_required_header, maybe_coerce_boolean as maybe_coerce_boolean, maybe_coerce_integer as maybe_coerce_integer, ) +from ._compat import ( + get_args as get_args, + is_union as is_union, + get_origin as get_origin, + is_typeddict as is_typeddict, + is_literal_type as is_literal_type, +) from ._typing import ( is_list_type as is_list_type, is_union_type as is_union_type, extract_type_arg as extract_type_arg, is_iterable_type as is_iterable_type, is_required_type as is_required_type, + is_sequence_type as is_sequence_type, is_annotated_type as is_annotated_type, + is_type_alias_type as is_type_alias_type, strip_annotated_type as strip_annotated_type, extract_type_var_from_base as extract_type_var_from_base, ) @@ -48,3 +57,8 @@ maybe_transform as maybe_transform, async_maybe_transform as async_maybe_transform, ) +from ._reflection import ( + function_has_argument as function_has_argument, + assert_signatures_in_sync as assert_signatures_in_sync, +) +from ._datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime diff --git a/src/orb/_utils/_compat.py b/src/orb/_utils/_compat.py new file mode 100644 index 00000000..2c70b299 --- /dev/null +++ b/src/orb/_utils/_compat.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +import sys +import typing_extensions +from typing import Any, Type, Union, Literal, Optional +from datetime import date, datetime +from typing_extensions import get_args as _get_args, get_origin as _get_origin + +from .._types import StrBytesIntFloat +from ._datetime_parse import parse_date as _parse_date, parse_datetime as _parse_datetime + +_LITERAL_TYPES = {Literal, typing_extensions.Literal} + + +def get_args(tp: type[Any]) -> tuple[Any, ...]: + return _get_args(tp) + + +def get_origin(tp: type[Any]) -> type[Any] | None: + return _get_origin(tp) + + +def is_union(tp: Optional[Type[Any]]) -> bool: + if sys.version_info < (3, 10): + return tp is Union # type: ignore[comparison-overlap] + else: + import types + + return tp is Union or tp is types.UnionType # type: ignore[comparison-overlap] + + +def is_typeddict(tp: Type[Any]) -> bool: + return typing_extensions.is_typeddict(tp) + + +def is_literal_type(tp: Type[Any]) -> bool: + return get_origin(tp) in _LITERAL_TYPES + + +def parse_date(value: Union[date, StrBytesIntFloat]) -> date: + return _parse_date(value) + + +def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + return _parse_datetime(value) diff --git a/src/orb/_utils/_datetime_parse.py b/src/orb/_utils/_datetime_parse.py new file mode 100644 index 00000000..7cb9d9e6 --- /dev/null +++ b/src/orb/_utils/_datetime_parse.py @@ -0,0 +1,136 @@ +""" +This file contains code from https://github.com/pydantic/pydantic/blob/main/pydantic/v1/datetime_parse.py +without the Pydantic v1 specific errors. +""" + +from __future__ import annotations + +import re +from typing import Dict, Union, Optional +from datetime import date, datetime, timezone, timedelta + +from .._types import StrBytesIntFloat + +date_expr = r"(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})" +time_expr = ( + r"(?P\d{1,2}):(?P\d{1,2})" + r"(?::(?P\d{1,2})(?:\.(?P\d{1,6})\d{0,6})?)?" + r"(?PZ|[+-]\d{2}(?::?\d{2})?)?$" +) + +date_re = re.compile(f"{date_expr}$") +datetime_re = re.compile(f"{date_expr}[T ]{time_expr}") + + +EPOCH = datetime(1970, 1, 1) +# if greater than this, the number is in ms, if less than or equal it's in seconds +# (in seconds this is 11th October 2603, in ms it's 20th August 1970) +MS_WATERSHED = int(2e10) +# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9 +MAX_NUMBER = int(3e20) + + +def _get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]: + if isinstance(value, (int, float)): + return value + try: + return float(value) + except ValueError: + return None + except TypeError: + raise TypeError(f"invalid type; expected {native_expected_type}, string, bytes, int or float") from None + + +def _from_unix_seconds(seconds: Union[int, float]) -> datetime: + if seconds > MAX_NUMBER: + return datetime.max + elif seconds < -MAX_NUMBER: + return datetime.min + + while abs(seconds) > MS_WATERSHED: + seconds /= 1000 + dt = EPOCH + timedelta(seconds=seconds) + return dt.replace(tzinfo=timezone.utc) + + +def _parse_timezone(value: Optional[str]) -> Union[None, int, timezone]: + if value == "Z": + return timezone.utc + elif value is not None: + offset_mins = int(value[-2:]) if len(value) > 3 else 0 + offset = 60 * int(value[1:3]) + offset_mins + if value[0] == "-": + offset = -offset + return timezone(timedelta(minutes=offset)) + else: + return None + + +def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + """ + Parse a datetime/int/float/string and return a datetime.datetime. + + This function supports time zone offsets. When the input contains one, + the output uses a timezone with a fixed offset from UTC. + + Raise ValueError if the input is well formatted but not a valid datetime. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, datetime): + return value + + number = _get_numeric(value, "datetime") + if number is not None: + return _from_unix_seconds(number) + + if isinstance(value, bytes): + value = value.decode() + + assert not isinstance(value, (float, int)) + + match = datetime_re.match(value) + if match is None: + raise ValueError("invalid datetime format") + + kw = match.groupdict() + if kw["microsecond"]: + kw["microsecond"] = kw["microsecond"].ljust(6, "0") + + tzinfo = _parse_timezone(kw.pop("tzinfo")) + kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} + kw_["tzinfo"] = tzinfo + + return datetime(**kw_) # type: ignore + + +def parse_date(value: Union[date, StrBytesIntFloat]) -> date: + """ + Parse a date/int/float/string and return a datetime.date. + + Raise ValueError if the input is well formatted but not a valid date. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, date): + if isinstance(value, datetime): + return value.date() + else: + return value + + number = _get_numeric(value, "date") + if number is not None: + return _from_unix_seconds(number).date() + + if isinstance(value, bytes): + value = value.decode() + + assert not isinstance(value, (float, int)) + match = date_re.match(value) + if match is None: + raise ValueError("invalid date format") + + kw = {k: int(v) for k, v in match.groupdict().items()} + + try: + return date(**kw) + except ValueError: + raise ValueError("invalid date format") from None diff --git a/src/orb/_utils/_json.py b/src/orb/_utils/_json.py new file mode 100644 index 00000000..60584214 --- /dev/null +++ b/src/orb/_utils/_json.py @@ -0,0 +1,35 @@ +import json +from typing import Any +from datetime import datetime +from typing_extensions import override + +import pydantic + +from .._compat import model_dump + + +def openapi_dumps(obj: Any) -> bytes: + """ + Serialize an object to UTF-8 encoded JSON bytes. + + Extends the standard json.dumps with support for additional types + commonly used in the SDK, such as `datetime`, `pydantic.BaseModel`, etc. + """ + return json.dumps( + obj, + cls=_CustomEncoder, + # Uses the same defaults as httpx's JSON serialization + ensure_ascii=False, + separators=(",", ":"), + allow_nan=False, + ).encode() + + +class _CustomEncoder(json.JSONEncoder): + @override + def default(self, o: Any) -> Any: + if isinstance(o, datetime): + return o.isoformat() + if isinstance(o, pydantic.BaseModel): + return model_dump(o, exclude_unset=True, mode="json", by_alias=True) + return super().default(o) diff --git a/src/orb/_utils/_path.py b/src/orb/_utils/_path.py new file mode 100644 index 00000000..4d6e1e4c --- /dev/null +++ b/src/orb/_utils/_path.py @@ -0,0 +1,127 @@ +from __future__ import annotations + +import re +from typing import ( + Any, + Mapping, + Callable, +) +from urllib.parse import quote + +# Matches '.' or '..' where each dot is either literal or percent-encoded (%2e / %2E). +_DOT_SEGMENT_RE = re.compile(r"^(?:\.|%2[eE]){1,2}$") + +_PLACEHOLDER_RE = re.compile(r"\{(\w+)\}") + + +def _quote_path_segment_part(value: str) -> str: + """Percent-encode `value` for use in a URI path segment. + + Considers characters not in `pchar` set from RFC 3986 §3.3 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.3 + """ + # quote() already treats unreserved characters (letters, digits, and -._~) + # as safe, so we only need to add sub-delims, ':', and '@'. + # Notably, unlike the default `safe` for quote(), / is unsafe and must be quoted. + return quote(value, safe="!$&'()*+,;=:@") + + +def _quote_query_part(value: str) -> str: + """Percent-encode `value` for use in a URI query string. + + Considers &, = and characters not in `query` set from RFC 3986 §3.4 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.4 + """ + return quote(value, safe="!$'()*+,;:@/?") + + +def _quote_fragment_part(value: str) -> str: + """Percent-encode `value` for use in a URI fragment. + + Considers characters not in `fragment` set from RFC 3986 §3.5 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.5 + """ + return quote(value, safe="!$&'()*+,;=:@/?") + + +def _interpolate( + template: str, + values: Mapping[str, Any], + quoter: Callable[[str], str], +) -> str: + """Replace {name} placeholders in `template`, quoting each value with `quoter`. + + Placeholder names are looked up in `values`. + + Raises: + KeyError: If a placeholder is not found in `values`. + """ + # re.split with a capturing group returns alternating + # [text, name, text, name, ..., text] elements. + parts = _PLACEHOLDER_RE.split(template) + + for i in range(1, len(parts), 2): + name = parts[i] + if name not in values: + raise KeyError(f"a value for placeholder {{{name}}} was not provided") + val = values[name] + if val is None: + parts[i] = "null" + elif isinstance(val, bool): + parts[i] = "true" if val else "false" + else: + parts[i] = quoter(str(values[name])) + + return "".join(parts) + + +def path_template(template: str, /, **kwargs: Any) -> str: + """Interpolate {name} placeholders in `template` from keyword arguments. + + Args: + template: The template string containing {name} placeholders. + **kwargs: Keyword arguments to interpolate into the template. + + Returns: + The template with placeholders interpolated and percent-encoded. + + Safe characters for percent-encoding are dependent on the URI component. + Placeholders in path and fragment portions are percent-encoded where the `segment` + and `fragment` sets from RFC 3986 respectively are considered safe. + Placeholders in the query portion are percent-encoded where the `query` set from + RFC 3986 §3.3 is considered safe except for = and & characters. + + Raises: + KeyError: If a placeholder is not found in `kwargs`. + ValueError: If resulting path contains /./ or /../ segments (including percent-encoded dot-segments). + """ + # Split the template into path, query, and fragment portions. + fragment_template: str | None = None + query_template: str | None = None + + rest = template + if "#" in rest: + rest, fragment_template = rest.split("#", 1) + if "?" in rest: + rest, query_template = rest.split("?", 1) + path_template = rest + + # Interpolate each portion with the appropriate quoting rules. + path_result = _interpolate(path_template, kwargs, _quote_path_segment_part) + + # Reject dot-segments (. and ..) in the final assembled path. The check + # runs after interpolation so that adjacent placeholders or a mix of static + # text and placeholders that together form a dot-segment are caught. + # Also reject percent-encoded dot-segments to protect against incorrectly + # implemented normalization in servers/proxies. + for segment in path_result.split("/"): + if _DOT_SEGMENT_RE.match(segment): + raise ValueError(f"Constructed path {path_result!r} contains dot-segment {segment!r} which is not allowed") + + result = path_result + if query_template is not None: + result += "?" + _interpolate(query_template, kwargs, _quote_query_part) + if fragment_template is not None: + result += "#" + _interpolate(fragment_template, kwargs, _quote_fragment_part) + + return result diff --git a/src/orb/_utils/_proxy.py b/src/orb/_utils/_proxy.py index b9c12dc3..0f239a33 100644 --- a/src/orb/_utils/_proxy.py +++ b/src/orb/_utils/_proxy.py @@ -10,7 +10,7 @@ class LazyProxy(Generic[T], ABC): """Implements data methods to pretend that an instance is another instance. - This includes forwarding attribute access and othe methods. + This includes forwarding attribute access and other methods. """ # Note: we have to special case proxies that themselves return proxies @@ -46,7 +46,10 @@ def __dir__(self) -> Iterable[str]: @property # type: ignore @override def __class__(self) -> type: # pyright: ignore - proxied = self.__get_proxied__() + try: + proxied = self.__get_proxied__() + except Exception: + return type(self) if issubclass(type(proxied), LazyProxy): return type(proxied) return proxied.__class__ @@ -59,5 +62,4 @@ def __as_proxied__(self) -> T: return cast(T, self) @abstractmethod - def __load__(self) -> T: - ... + def __load__(self) -> T: ... diff --git a/src/orb/_utils/_reflection.py b/src/orb/_utils/_reflection.py new file mode 100644 index 00000000..89aa712a --- /dev/null +++ b/src/orb/_utils/_reflection.py @@ -0,0 +1,42 @@ +from __future__ import annotations + +import inspect +from typing import Any, Callable + + +def function_has_argument(func: Callable[..., Any], arg_name: str) -> bool: + """Returns whether or not the given function has a specific parameter""" + sig = inspect.signature(func) + return arg_name in sig.parameters + + +def assert_signatures_in_sync( + source_func: Callable[..., Any], + check_func: Callable[..., Any], + *, + exclude_params: set[str] = set(), +) -> None: + """Ensure that the signature of the second function matches the first.""" + + check_sig = inspect.signature(check_func) + source_sig = inspect.signature(source_func) + + errors: list[str] = [] + + for name, source_param in source_sig.parameters.items(): + if name in exclude_params: + continue + + custom_param = check_sig.parameters.get(name) + if not custom_param: + errors.append(f"the `{name}` param is missing") + continue + + if custom_param.annotation != source_param.annotation: + errors.append( + f"types for the `{name}` param are do not match; source={repr(source_param.annotation)} checking={repr(custom_param.annotation)}" + ) + continue + + if errors: + raise AssertionError(f"{len(errors)} errors encountered when comparing signatures:\n\n" + "\n\n".join(errors)) diff --git a/src/orb/_utils/_resources_proxy.py b/src/orb/_utils/_resources_proxy.py new file mode 100644 index 00000000..a12180a0 --- /dev/null +++ b/src/orb/_utils/_resources_proxy.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from typing import Any +from typing_extensions import override + +from ._proxy import LazyProxy + + +class ResourcesProxy(LazyProxy[Any]): + """A proxy for the `orb.resources` module. + + This is used so that we can lazily import `orb.resources` only when + needed *and* so that users can just import `orb` and reference `orb.resources` + """ + + @override + def __load__(self) -> Any: + import importlib + + mod = importlib.import_module("orb.resources") + return mod + + +resources = ResourcesProxy().__as_proxied__() diff --git a/src/orb/_utils/_sync.py b/src/orb/_utils/_sync.py index 595924e5..f6027c18 100644 --- a/src/orb/_utils/_sync.py +++ b/src/orb/_utils/_sync.py @@ -1,54 +1,49 @@ from __future__ import annotations +import asyncio import functools from typing import TypeVar, Callable, Awaitable from typing_extensions import ParamSpec import anyio +import sniffio import anyio.to_thread 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]]: +async def to_thread( + func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs +) -> T_Retval: + if sniffio.current_async_library() == "asyncio": + return await asyncio.to_thread(func, *args, **kwargs) + + return await anyio.to_thread.run_sync( + functools.partial(func, *args, **kwargs), + ) + + +# 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. - 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 @@ -58,7 +53,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) - 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 47e262a5..52075492 100644 --- a/src/orb/_utils/_transform.py +++ b/src/orb/_utils/_transform.py @@ -5,27 +5,31 @@ import pathlib from typing import Any, Mapping, TypeVar, cast from datetime import date, datetime -from typing_extensions import Literal, get_args, override, get_type_hints +from typing_extensions import Literal, get_args, override, get_type_hints as _get_type_hints import anyio import pydantic from ._utils import ( is_list, + is_given, + lru_cache, is_mapping, is_iterable, + is_sequence, ) from .._files import is_base64_file_input +from ._compat import get_origin, is_typeddict from ._typing import ( is_list_type, is_union_type, extract_type_arg, is_iterable_type, is_required_type, + is_sequence_type, is_annotated_type, strip_annotated_type, ) -from .._compat import model_dump, is_typeddict _T = TypeVar("_T") @@ -108,6 +112,7 @@ class Params(TypedDict, total=False): return cast(_T, transformed) +@lru_cache(maxsize=8096) def _get_annotated_type(type_: type) -> type | None: """If the given type is an `Annotated` type then it is returned, if not `None` is returned. @@ -126,7 +131,7 @@ def _get_annotated_type(type_: type) -> type | None: def _maybe_transform_key(key: str, type_: type) -> str: """Transform the given `data` based on the annotations provided in `type_`. - Note: this function only looks at `Annotated` types that contain `PropertInfo` metadata. + Note: this function only looks at `Annotated` types that contain `PropertyInfo` metadata. """ annotated_type = _get_annotated_type(type_) if annotated_type is None: @@ -142,6 +147,10 @@ def _maybe_transform_key(key: str, type_: type) -> str: return key +def _no_transform_needed(annotation: type) -> bool: + return annotation == float or annotation == int + + def _transform_recursive( data: object, *, @@ -160,20 +169,43 @@ def _transform_recursive( Defaults to the same value as the `annotation` argument. """ + from .._compat import model_dump + if inner_type is None: inner_type = annotation stripped_type = strip_annotated_type(inner_type) + origin = get_origin(stripped_type) or stripped_type if is_typeddict(stripped_type) and is_mapping(data): return _transform_typeddict(data, stripped_type) + if origin == dict and is_mapping(data): + items_type = get_args(stripped_type)[1] + return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} + if ( # List[T] (is_list_type(stripped_type) and is_list(data)) # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + # Sequence[T] + or (is_sequence_type(stripped_type) and is_sequence(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) + if _no_transform_needed(inner_type): + # for some types there is no need to transform anything, so we can get a small + # perf boost from skipping that work. + # + # but we still need to convert to a list to ensure the data is json-serializable + if is_list(data): + return data + return list(data) + return [_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] if is_union_type(stripped_type): @@ -186,7 +218,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: @@ -235,6 +267,11 @@ def _transform_typeddict( result: dict[str, object] = {} annotations = get_type_hints(expected_type, include_extras=True) for key, value in data.items(): + if not is_given(value): + # we don't need to include omitted values here as they'll + # be stripped out before the request is sent anyway + continue + type_ = annotations.get(key) if type_ is None: # we do not have a type annotation for this field, leave it as is @@ -298,20 +335,43 @@ async def _async_transform_recursive( Defaults to the same value as the `annotation` argument. """ + from .._compat import model_dump + if inner_type is None: inner_type = annotation stripped_type = strip_annotated_type(inner_type) + origin = get_origin(stripped_type) or stripped_type if is_typeddict(stripped_type) and is_mapping(data): return await _async_transform_typeddict(data, stripped_type) + if origin == dict and is_mapping(data): + items_type = get_args(stripped_type)[1] + return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} + if ( # List[T] (is_list_type(stripped_type) and is_list(data)) # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + # Sequence[T] + or (is_sequence_type(stripped_type) and is_sequence(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) + if _no_transform_needed(inner_type): + # for some types there is no need to transform anything, so we can get a small + # perf boost from skipping that work. + # + # but we still need to convert to a list to ensure the data is json-serializable + if is_list(data): + return data + return list(data) + return [await _async_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] if is_union_type(stripped_type): @@ -324,7 +384,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: @@ -373,6 +433,11 @@ async def _async_transform_typeddict( result: dict[str, object] = {} annotations = get_type_hints(expected_type, include_extras=True) for key, value in data.items(): + if not is_given(value): + # we don't need to include omitted values here as they'll + # be stripped out before the request is sent anyway + continue + type_ = annotations.get(key) if type_ is None: # we do not have a type annotation for this field, leave it as is @@ -380,3 +445,13 @@ async def _async_transform_typeddict( else: result[_maybe_transform_key(key, type_)] = await _async_transform_recursive(value, annotation=type_) return result + + +@lru_cache(maxsize=8096) +def get_type_hints( + obj: Any, + globalns: dict[str, Any] | None = None, + localns: Mapping[str, Any] | None = None, + include_extras: bool = False, +) -> dict[str, Any]: + return _get_type_hints(obj, globalns=globalns, localns=localns, include_extras=include_extras) diff --git a/src/orb/_utils/_typing.py b/src/orb/_utils/_typing.py index c036991f..193109f3 100644 --- a/src/orb/_utils/_typing.py +++ b/src/orb/_utils/_typing.py @@ -1,11 +1,21 @@ from __future__ import annotations +import sys +import typing +import typing_extensions from typing import Any, TypeVar, Iterable, cast from collections import abc as _c_abc -from typing_extensions import Required, Annotated, get_args, get_origin - +from typing_extensions import ( + TypeIs, + Required, + Annotated, + get_args, + get_origin, +) + +from ._utils import lru_cache from .._types import InheritsGeneric -from .._compat import is_union as _is_union +from ._compat import is_union as _is_union def is_annotated_type(typ: type) -> bool: @@ -16,6 +26,11 @@ def is_list_type(typ: type) -> bool: return (get_origin(typ) or typ) == list +def is_sequence_type(typ: type) -> bool: + origin = get_origin(typ) or typ + return origin == typing_extensions.Sequence or origin == typing.Sequence or origin == _c_abc.Sequence + + def is_iterable_type(typ: type) -> bool: """If the given type is `typing.Iterable[T]`""" origin = get_origin(typ) or typ @@ -36,7 +51,28 @@ def is_typevar(typ: type) -> bool: return type(typ) == TypeVar # type: ignore +_TYPE_ALIAS_TYPES: tuple[type[typing_extensions.TypeAliasType], ...] = (typing_extensions.TypeAliasType,) +if sys.version_info >= (3, 12): + _TYPE_ALIAS_TYPES = (*_TYPE_ALIAS_TYPES, typing.TypeAliasType) + + +def is_type_alias_type(tp: Any, /) -> TypeIs[typing_extensions.TypeAliasType]: + """Return whether the provided argument is an instance of `TypeAliasType`. + + ```python + type Int = int + is_type_alias_type(Int) + # > True + Str = TypeAliasType("Str", str) + is_type_alias_type(Str) + # > True + ``` + """ + return isinstance(tp, _TYPE_ALIAS_TYPES) + + # Extracts T from Annotated[T, ...] or from Required[Annotated[T, ...]] +@lru_cache(maxsize=8096) def strip_annotated_type(typ: type) -> type: if is_required_type(typ) or is_annotated_type(typ): return strip_annotated_type(cast(type, get_args(typ)[0])) @@ -79,7 +115,7 @@ class MyResponse(Foo[_T]): ``` """ cls = cast(object, get_origin(typ) or typ) - if cls in generic_bases: + if cls in generic_bases: # pyright: ignore[reportUnnecessaryContains] # we're given the class directly return extract_type_arg(typ, index) diff --git a/src/orb/_utils/_utils.py b/src/orb/_utils/_utils.py index 93c95517..199cd231 100644 --- a/src/orb/_utils/_utils.py +++ b/src/orb/_utils/_utils.py @@ -16,12 +16,12 @@ overload, ) from pathlib import Path -from typing_extensions import TypeGuard +from datetime import date, datetime +from typing_extensions import TypeGuard, get_args import sniffio -from .._types import Headers, NotGiven, FileTypes, NotGivenOr, HeadersLike -from .._compat import parse_date as parse_date, parse_datetime as parse_datetime +from .._types import Omit, NotGiven, FileTypes, ArrayFormat, HeadersLike _T = TypeVar("_T") _TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) @@ -40,30 +40,50 @@ def extract_files( query: Mapping[str, object], *, paths: Sequence[Sequence[str]], + array_format: ArrayFormat = "brackets", ) -> list[tuple[str, FileTypes]]: """Recursively extract files from the given dictionary based on specified paths. A path may look like this ['foo', 'files', '', 'data']. + ``array_format`` controls how ```` segments contribute to the emitted + field name. Supported values: ``"brackets"`` (``foo[]``), ``"repeat"`` and + ``"comma"`` (``foo``), ``"indices"`` (``foo[0]``, ``foo[1]``). + Note: this mutates the given dictionary. """ files: list[tuple[str, FileTypes]] = [] for path in paths: - files.extend(_extract_items(query, path, index=0, flattened_key=None)) + files.extend(_extract_items(query, path, index=0, flattened_key=None, array_format=array_format)) return files +def _array_suffix(array_format: ArrayFormat, array_index: int) -> str: + if array_format == "brackets": + return "[]" + if array_format == "indices": + return f"[{array_index}]" + if array_format == "repeat" or array_format == "comma": + # Both repeat the bare field name for each file part; there is no + # meaningful way to comma-join binary parts. + return "" + raise NotImplementedError( + f"Unknown array_format value: {array_format}, choose from {', '.join(get_args(ArrayFormat))}" + ) + + def _extract_items( obj: object, path: Sequence[str], *, index: int, flattened_key: str | None, + array_format: ArrayFormat, ) -> list[tuple[str, FileTypes]]: try: key = path[index] except IndexError: - if isinstance(obj, NotGiven): + if not is_given(obj): # no value was provided - we can safely ignore return [] @@ -71,15 +91,26 @@ def _extract_items( from .._files import assert_is_file_content # We have exhausted the path, return the entry we found. - assert_is_file_content(obj, key=flattened_key) assert flattened_key is not None + + if is_list(obj): + files: list[tuple[str, FileTypes]] = [] + for array_index, entry in enumerate(obj): + suffix = _array_suffix(array_format, array_index) + emitted_key = (flattened_key + suffix) if flattened_key else suffix + assert_is_file_content(entry, key=emitted_key) + files.append((emitted_key, cast(FileTypes, entry))) + return files + + assert_is_file_content(obj, key=flattened_key) return [(flattened_key, cast(FileTypes, obj))] index += 1 if is_dict(obj): try: - # We are at the last entry in the path so we must remove the field - if (len(path)) == index: + # Remove the field if there are no more dict keys in the path, + # only "" traversal markers or end. + if all(p == "" for p in path[index:]): item = obj.pop(key) else: item = obj[key] @@ -97,6 +128,7 @@ def _extract_items( path, index=index, flattened_key=flattened_key, + array_format=array_format, ) elif is_list(obj): if key != "": @@ -108,9 +140,12 @@ def _extract_items( item, path, index=index, - flattened_key=flattened_key + "[]" if flattened_key is not None else "[]", + flattened_key=( + (flattened_key if flattened_key is not None else "") + _array_suffix(array_format, array_index) + ), + array_format=array_format, ) - for item in obj + for array_index, item in enumerate(obj) ] ) @@ -118,14 +153,14 @@ def _extract_items( return [] -def is_given(obj: NotGivenOr[_T]) -> TypeGuard[_T]: - return not isinstance(obj, NotGiven) +def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]: + return not isinstance(obj, NotGiven) and not isinstance(obj, Omit) # Type safe methods for narrowing types with TypeVars. # The default narrowing for isinstance(obj, dict) is dict[unknown, unknown], # however this cause Pyright to rightfully report errors. As we know we don't -# care about the contained types we can safely use `object` in it's place. +# care about the contained types we can safely use `object` in its place. # # There are two separate functions defined, `is_*` and `is_*_t` for different use cases. # `is_*` is for when you're dealing with an unknown input @@ -168,21 +203,6 @@ def is_iterable(obj: object) -> TypeGuard[Iterable[object]]: return isinstance(obj, Iterable) -def deepcopy_minimal(item: _T) -> _T: - """Minimal reimplementation of copy.deepcopy() that will only copy certain object types: - - - mappings, e.g. `dict` - - list - - This is done for performance reasons. - """ - if is_mapping(item): - return cast(_T, {k: deepcopy_minimal(v) for k, v in item.items()}) - if is_list(item): - return cast(_T, [deepcopy_minimal(entry) for entry in item]) - return item - - # copied from https://github.com/Rapptz/RoboDanny def human_join(seq: Sequence[str], *, delim: str = ", ", final: str = "or") -> str: size = len(seq) @@ -211,20 +231,17 @@ def required_args(*variants: Sequence[str]) -> Callable[[CallableT], CallableT]: Example usage: ```py @overload - def foo(*, a: str) -> str: - ... + def foo(*, a: str) -> str: ... @overload - def foo(*, b: bool) -> str: - ... + def foo(*, b: bool) -> str: ... # This enforces the same constraints that a static type checker would # i.e. that either a or b must be passed to the function @required_args(["a"], ["b"]) - def foo(*, a: str | None = None, b: bool | None = None) -> str: - ... + def foo(*, a: str | None = None, b: bool | None = None) -> str: ... ``` """ @@ -265,6 +282,8 @@ def wrapper(*args: object, **kwargs: object) -> object: ) msg = f"Missing required arguments; Expected either {variations} arguments to be given" else: + assert len(variants) > 0 + # TODO: this error message is not deterministic missing = list(set(variants[0]) - given_params) if len(missing) > 1: @@ -284,18 +303,15 @@ def wrapper(*args: object, **kwargs: object) -> object: @overload -def strip_not_given(obj: None) -> None: - ... +def strip_not_given(obj: None) -> None: ... @overload -def strip_not_given(obj: Mapping[_K, _V | NotGiven]) -> dict[_K, _V]: - ... +def strip_not_given(obj: Mapping[_K, _V | NotGiven]) -> dict[_K, _V]: ... @overload -def strip_not_given(obj: object) -> object: - ... +def strip_not_given(obj: object) -> object: ... def strip_not_given(obj: object | None) -> object: @@ -367,13 +383,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): - headers = cast(Headers, headers) - 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]: @@ -389,3 +405,29 @@ def get_async_library() -> str: return sniffio.current_async_library() except Exception: return "false" + + +def lru_cache(*, maxsize: int | None = 128) -> Callable[[CallableT], CallableT]: + """A version of functools.lru_cache that retains the type signature + for the wrapped function arguments. + """ + wrapper = functools.lru_cache( # noqa: TID251 + 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 03c6e622..aca24df9 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__ = "1.47.1" # x-release-please-version +__version__ = "4.55.2" # x-release-please-version diff --git a/src/orb/pagination.py b/src/orb/pagination.py index df68690f..61cc363c 100644 --- a/src/orb/pagination.py +++ b/src/orb/pagination.py @@ -32,7 +32,8 @@ def _get_page_items(self) -> List[_T]: def next_page_info(self) -> Optional[PageInfo]: next_cursor = None if self.pagination_metadata is not None: # pyright: ignore[reportUnnecessaryComparison] - next_cursor = self.pagination_metadata.next_cursor + if self.pagination_metadata.next_cursor is not None: + next_cursor = self.pagination_metadata.next_cursor if not next_cursor: return None @@ -54,7 +55,8 @@ def _get_page_items(self) -> List[_T]: def next_page_info(self) -> Optional[PageInfo]: next_cursor = None if self.pagination_metadata is not None: # pyright: ignore[reportUnnecessaryComparison] - next_cursor = self.pagination_metadata.next_cursor + if self.pagination_metadata.next_cursor is not None: + next_cursor = self.pagination_metadata.next_cursor if not next_cursor: return None diff --git a/src/orb/resources/__init__.py b/src/orb/resources/__init__.py index 4d1688e6..6bf44770 100644 --- a/src/orb/resources/__init__.py +++ b/src/orb/resources/__init__.py @@ -24,6 +24,14 @@ PlansWithStreamingResponse, AsyncPlansWithStreamingResponse, ) +from .alerts import ( + Alerts, + AsyncAlerts, + AlertsWithRawResponse, + AsyncAlertsWithRawResponse, + AlertsWithStreamingResponse, + AsyncAlertsWithStreamingResponse, +) from .events import ( Events, AsyncEvents, @@ -64,6 +72,14 @@ InvoicesWithStreamingResponse, AsyncInvoicesWithStreamingResponse, ) +from .licenses import ( + Licenses, + AsyncLicenses, + LicensesWithRawResponse, + AsyncLicensesWithRawResponse, + LicensesWithStreamingResponse, + AsyncLicensesWithStreamingResponse, +) from .customers import ( Customers, AsyncCustomers, @@ -88,6 +104,22 @@ CreditNotesWithStreamingResponse, AsyncCreditNotesWithStreamingResponse, ) +from .credit_blocks import ( + CreditBlocks, + AsyncCreditBlocks, + CreditBlocksWithRawResponse, + AsyncCreditBlocksWithRawResponse, + CreditBlocksWithStreamingResponse, + AsyncCreditBlocksWithStreamingResponse, +) +from .license_types import ( + LicenseTypes, + AsyncLicenseTypes, + LicenseTypesWithRawResponse, + AsyncLicenseTypesWithRawResponse, + LicenseTypesWithStreamingResponse, + AsyncLicenseTypesWithStreamingResponse, +) from .subscriptions import ( Subscriptions, AsyncSubscriptions, @@ -104,6 +136,22 @@ InvoiceLineItemsWithStreamingResponse, AsyncInvoiceLineItemsWithStreamingResponse, ) +from .subscription_changes import ( + SubscriptionChanges, + AsyncSubscriptionChanges, + SubscriptionChangesWithRawResponse, + AsyncSubscriptionChangesWithRawResponse, + SubscriptionChangesWithStreamingResponse, + AsyncSubscriptionChangesWithStreamingResponse, +) +from .dimensional_price_groups import ( + DimensionalPriceGroups, + AsyncDimensionalPriceGroups, + DimensionalPriceGroupsWithRawResponse, + AsyncDimensionalPriceGroupsWithRawResponse, + DimensionalPriceGroupsWithStreamingResponse, + AsyncDimensionalPriceGroupsWithStreamingResponse, +) __all__ = [ "TopLevel", @@ -112,6 +160,12 @@ "AsyncTopLevelWithRawResponse", "TopLevelWithStreamingResponse", "AsyncTopLevelWithStreamingResponse", + "Beta", + "AsyncBeta", + "BetaWithRawResponse", + "AsyncBetaWithRawResponse", + "BetaWithStreamingResponse", + "AsyncBetaWithStreamingResponse", "Coupons", "AsyncCoupons", "CouponsWithRawResponse", @@ -178,10 +232,40 @@ "AsyncSubscriptionsWithRawResponse", "SubscriptionsWithStreamingResponse", "AsyncSubscriptionsWithStreamingResponse", - "Beta", - "AsyncBeta", - "BetaWithRawResponse", - "AsyncBetaWithRawResponse", - "BetaWithStreamingResponse", - "AsyncBetaWithStreamingResponse", + "Alerts", + "AsyncAlerts", + "AlertsWithRawResponse", + "AsyncAlertsWithRawResponse", + "AlertsWithStreamingResponse", + "AsyncAlertsWithStreamingResponse", + "DimensionalPriceGroups", + "AsyncDimensionalPriceGroups", + "DimensionalPriceGroupsWithRawResponse", + "AsyncDimensionalPriceGroupsWithRawResponse", + "DimensionalPriceGroupsWithStreamingResponse", + "AsyncDimensionalPriceGroupsWithStreamingResponse", + "SubscriptionChanges", + "AsyncSubscriptionChanges", + "SubscriptionChangesWithRawResponse", + "AsyncSubscriptionChangesWithRawResponse", + "SubscriptionChangesWithStreamingResponse", + "AsyncSubscriptionChangesWithStreamingResponse", + "CreditBlocks", + "AsyncCreditBlocks", + "CreditBlocksWithRawResponse", + "AsyncCreditBlocksWithRawResponse", + "CreditBlocksWithStreamingResponse", + "AsyncCreditBlocksWithStreamingResponse", + "LicenseTypes", + "AsyncLicenseTypes", + "LicenseTypesWithRawResponse", + "AsyncLicenseTypesWithRawResponse", + "LicenseTypesWithStreamingResponse", + "AsyncLicenseTypesWithStreamingResponse", + "Licenses", + "AsyncLicenses", + "LicensesWithRawResponse", + "AsyncLicensesWithRawResponse", + "LicensesWithStreamingResponse", + "AsyncLicensesWithStreamingResponse", ] diff --git a/src/orb/resources/alerts.py b/src/orb/resources/alerts.py new file mode 100644 index 00000000..bf895d1d --- /dev/null +++ b/src/orb/resources/alerts.py @@ -0,0 +1,1203 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from .. import _legacy_response +from ..types import ( + alert_list_params, + alert_enable_params, + alert_update_params, + alert_disable_params, + alert_create_for_customer_params, + alert_create_for_subscription_params, + alert_create_for_external_customer_params, +) +from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from .._utils import path_template, 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 ..pagination import SyncPage, AsyncPage +from ..types.alert import Alert +from .._base_client import AsyncPaginator, make_request_options +from ..types.threshold_param import ThresholdParam + +__all__ = ["Alerts", "AsyncAlerts"] + + +class Alerts(SyncAPIResource): + """ + [Alerts within Orb](/product-catalog/configuring-alerts) monitor spending, + usage, or credit balance and trigger webhooks when a threshold is exceeded. + + Alerts created through the API can be scoped to either customers or subscriptions. + """ + + @cached_property + def with_raw_response(self) -> AlertsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( + self, + alert_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Alert: + """ + This endpoint retrieves an alert by its ID. + + Args: + 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 + """ + if not alert_id: + raise ValueError(f"Expected a non-empty value for `alert_id` but received {alert_id!r}") + return self._get( + path_template("/alerts/{alert_id}", alert_id=alert_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Alert, + ) + + def update( + self, + alert_configuration_id: str, + *, + thresholds: Iterable[ThresholdParam], + price_filters: Optional[Iterable[alert_update_params.PriceFilter]] | Omit = omit, + threshold_overrides: Optional[Iterable[alert_update_params.ThresholdOverride]] | Omit = omit, + # 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, + ) -> Alert: + """ + This endpoint updates the thresholds of an alert. + + Args: + thresholds: The thresholds that define the values at which the alert will be triggered. + + price_filters: Replaces the price filters on a grouped cost alert; an empty list clears them. + Only applicable to cost alerts with grouping_keys. Omit to leave unchanged. + + threshold_overrides: Replaces the per-group threshold overrides on a grouped cost alert; an empty + list clears them. Only applicable to cost alerts with grouping_keys. Omit to + leave unchanged. + + 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 alert_configuration_id: + raise ValueError( + f"Expected a non-empty value for `alert_configuration_id` but received {alert_configuration_id!r}" + ) + return self._put( + path_template("/alerts/{alert_configuration_id}", alert_configuration_id=alert_configuration_id), + body=maybe_transform( + { + "thresholds": thresholds, + "price_filters": price_filters, + "threshold_overrides": threshold_overrides, + }, + alert_update_params.AlertUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Alert, + ) + + def list( + self, + *, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + cursor: Optional[str] | Omit = omit, + customer_id: Optional[str] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + limit: int | Omit = omit, + subscription_id: Optional[str] | Omit = omit, + # 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, + ) -> SyncPage[Alert]: + """ + This endpoint returns a list of alerts within Orb. + + The request must specify one of `customer_id`, `external_customer_id`, or + `subscription_id`. + + If querying by subscription_id, the endpoint will return the subscription level + alerts as well as the plan level alerts associated with the subscription. + + The list of alerts is ordered starting from the most recently created alert. + This endpoint follows Orb's + [standardized pagination format](/api-reference/pagination). + + Args: + cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned + from the initial request. + + customer_id: Fetch alerts scoped to this customer_id + + external_customer_id: Fetch alerts scoped to this external_customer_id + + limit: The number of items to fetch. Defaults to 20. + + subscription_id: Fetch alerts scoped to this subscription_id + + 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_api_list( + "/alerts", + page=SyncPage[Alert], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "created_at_gt": created_at_gt, + "created_at_gte": created_at_gte, + "created_at_lt": created_at_lt, + "created_at_lte": created_at_lte, + "cursor": cursor, + "customer_id": customer_id, + "external_customer_id": external_customer_id, + "limit": limit, + "subscription_id": subscription_id, + }, + alert_list_params.AlertListParams, + ), + ), + model=Alert, + ) + + def create_for_customer( + self, + customer_id: str, + *, + currency: str, + type: Literal["credit_balance_depleted", "credit_balance_dropped", "credit_balance_recovered"], + thresholds: Optional[Iterable[ThresholdParam]] | Omit = omit, + # 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, + ) -> Alert: + """This endpoint creates a new alert to monitor a customer's credit balance. + + There + are three types of alerts that can be scoped to customers: + `credit_balance_depleted`, `credit_balance_dropped`, and + `credit_balance_recovered`. Customers can have a maximum of one of each type of + alert per [credit balance currency](/product-catalog/prepurchase). + `credit_balance_dropped` alerts require a list of thresholds to be provided + while `credit_balance_depleted` and `credit_balance_recovered` alerts do not + require thresholds. + + Args: + currency: The case sensitive currency or custom pricing unit to use for this alert. + + type: The type of alert to create. This must be a valid alert type. + + thresholds: The thresholds that define the values at which the alert will be triggered. + + 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 customer_id: + raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") + return self._post( + path_template("/alerts/customer_id/{customer_id}", customer_id=customer_id), + body=maybe_transform( + { + "currency": currency, + "type": type, + "thresholds": thresholds, + }, + alert_create_for_customer_params.AlertCreateForCustomerParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Alert, + ) + + def create_for_external_customer( + self, + external_customer_id: str, + *, + currency: str, + type: Literal["credit_balance_depleted", "credit_balance_dropped", "credit_balance_recovered"], + thresholds: Optional[Iterable[ThresholdParam]] | Omit = omit, + # 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, + ) -> Alert: + """This endpoint creates a new alert to monitor a customer's credit balance. + + There + are three types of alerts that can be scoped to customers: + `credit_balance_depleted`, `credit_balance_dropped`, and + `credit_balance_recovered`. Customers can have a maximum of one of each type of + alert per [credit balance currency](/product-catalog/prepurchase). + `credit_balance_dropped` alerts require a list of thresholds to be provided + while `credit_balance_depleted` and `credit_balance_recovered` alerts do not + require thresholds. + + Args: + currency: The case sensitive currency or custom pricing unit to use for this alert. + + type: The type of alert to create. This must be a valid alert type. + + thresholds: The thresholds that define the values at which the alert will be triggered. + + 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 external_customer_id: + raise ValueError( + f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" + ) + return self._post( + path_template( + "/alerts/external_customer_id/{external_customer_id}", external_customer_id=external_customer_id + ), + body=maybe_transform( + { + "currency": currency, + "type": type, + "thresholds": thresholds, + }, + alert_create_for_external_customer_params.AlertCreateForExternalCustomerParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Alert, + ) + + def create_for_subscription( + self, + subscription_id: str, + *, + thresholds: Iterable[ThresholdParam], + type: Literal["usage_exceeded", "cost_exceeded"], + currency: Optional[str] | Omit = omit, + grouping_keys: Optional[SequenceNotStr[str]] | Omit = omit, + metric_id: Optional[str] | Omit = omit, + price_filters: Optional[Iterable[alert_create_for_subscription_params.PriceFilter]] | Omit = omit, + threshold_overrides: Optional[Iterable[alert_create_for_subscription_params.ThresholdOverride]] | Omit = omit, + # 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, + ) -> Alert: + """ + This endpoint is used to create alerts at the subscription level. + + Subscription level alerts can be one of two types: `usage_exceeded` or + `cost_exceeded`. A `usage_exceeded` alert is scoped to a particular metric and + is triggered when the usage of that metric exceeds predefined thresholds during + the current billing cycle. A `cost_exceeded` alert is triggered when the total + amount due during the current billing cycle surpasses predefined thresholds. + `cost_exceeded` alerts do not include burndown of pre-purchase credits. Each + subscription can have one `cost_exceeded` alert and one `usage_exceeded` alert + per metric that is a part of the subscription. Alerts are triggered based on + usage or cost conditions met during the current billing cycle. + + Args: + thresholds: The thresholds that define the values at which the alert will be triggered. + + type: The type of alert to create. This must be a valid alert type. + + currency: The case sensitive currency or custom pricing unit to use for grouped cost + alerts. Required when grouping_keys is set. + + grouping_keys: The property keys to group cost alerts by. Only applicable for cost_exceeded + alerts. + + metric_id: The metric to track usage for. + + price_filters: Filters to scope which prices are included in grouped cost alert evaluation. + Supports filtering by price_id, item_id, or price_type with includes/excludes + operators. Only applicable when grouping_keys is set. + + threshold_overrides: Per-group threshold overrides. Each override maps a specific combination of + grouping_keys values to a list of thresholds that fully replaces the default + thresholds for that group. An empty thresholds list silences the group. Groups + without an override use the default thresholds. Only applicable when + grouping_keys is set. + + 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( + path_template("/alerts/subscription_id/{subscription_id}", subscription_id=subscription_id), + body=maybe_transform( + { + "thresholds": thresholds, + "type": type, + "currency": currency, + "grouping_keys": grouping_keys, + "metric_id": metric_id, + "price_filters": price_filters, + "threshold_overrides": threshold_overrides, + }, + alert_create_for_subscription_params.AlertCreateForSubscriptionParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Alert, + ) + + def disable( + self, + alert_configuration_id: str, + *, + subscription_id: Optional[str] | Omit = omit, + # 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, + ) -> Alert: + """This endpoint allows you to disable an alert. + + To disable a plan-level alert for + a specific subscription, you must include the `subscription_id`. The + `subscription_id` is not required for customer or subscription level alerts. + + Args: + subscription_id: Used to update the status of a plan alert scoped to this subscription_id + + 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 alert_configuration_id: + raise ValueError( + f"Expected a non-empty value for `alert_configuration_id` but received {alert_configuration_id!r}" + ) + return self._post( + path_template("/alerts/{alert_configuration_id}/disable", alert_configuration_id=alert_configuration_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + query=maybe_transform({"subscription_id": subscription_id}, alert_disable_params.AlertDisableParams), + ), + cast_to=Alert, + ) + + def enable( + self, + alert_configuration_id: str, + *, + subscription_id: Optional[str] | Omit = omit, + # 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, + ) -> Alert: + """This endpoint allows you to enable an alert. + + To enable a plan-level alert for a + specific subscription, you must include the `subscription_id`. The + `subscription_id` is not required for customer or subscription level alerts. + + Args: + subscription_id: Used to update the status of a plan alert scoped to this subscription_id + + 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 alert_configuration_id: + raise ValueError( + f"Expected a non-empty value for `alert_configuration_id` but received {alert_configuration_id!r}" + ) + return self._post( + path_template("/alerts/{alert_configuration_id}/enable", alert_configuration_id=alert_configuration_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + query=maybe_transform({"subscription_id": subscription_id}, alert_enable_params.AlertEnableParams), + ), + cast_to=Alert, + ) + + +class AsyncAlerts(AsyncAPIResource): + """ + [Alerts within Orb](/product-catalog/configuring-alerts) monitor spending, + usage, or credit balance and trigger webhooks when a threshold is exceeded. + + Alerts created through the API can be scoped to either customers or subscriptions. + """ + + @cached_property + def with_raw_response(self) -> AsyncAlertsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( + self, + alert_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Alert: + """ + This endpoint retrieves an alert by its ID. + + Args: + 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 + """ + if not alert_id: + raise ValueError(f"Expected a non-empty value for `alert_id` but received {alert_id!r}") + return await self._get( + path_template("/alerts/{alert_id}", alert_id=alert_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Alert, + ) + + async def update( + self, + alert_configuration_id: str, + *, + thresholds: Iterable[ThresholdParam], + price_filters: Optional[Iterable[alert_update_params.PriceFilter]] | Omit = omit, + threshold_overrides: Optional[Iterable[alert_update_params.ThresholdOverride]] | Omit = omit, + # 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, + ) -> Alert: + """ + This endpoint updates the thresholds of an alert. + + Args: + thresholds: The thresholds that define the values at which the alert will be triggered. + + price_filters: Replaces the price filters on a grouped cost alert; an empty list clears them. + Only applicable to cost alerts with grouping_keys. Omit to leave unchanged. + + threshold_overrides: Replaces the per-group threshold overrides on a grouped cost alert; an empty + list clears them. Only applicable to cost alerts with grouping_keys. Omit to + leave unchanged. + + 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 alert_configuration_id: + raise ValueError( + f"Expected a non-empty value for `alert_configuration_id` but received {alert_configuration_id!r}" + ) + return await self._put( + path_template("/alerts/{alert_configuration_id}", alert_configuration_id=alert_configuration_id), + body=await async_maybe_transform( + { + "thresholds": thresholds, + "price_filters": price_filters, + "threshold_overrides": threshold_overrides, + }, + alert_update_params.AlertUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Alert, + ) + + def list( + self, + *, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + cursor: Optional[str] | Omit = omit, + customer_id: Optional[str] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + limit: int | Omit = omit, + subscription_id: Optional[str] | Omit = omit, + # 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, + ) -> AsyncPaginator[Alert, AsyncPage[Alert]]: + """ + This endpoint returns a list of alerts within Orb. + + The request must specify one of `customer_id`, `external_customer_id`, or + `subscription_id`. + + If querying by subscription_id, the endpoint will return the subscription level + alerts as well as the plan level alerts associated with the subscription. + + The list of alerts is ordered starting from the most recently created alert. + This endpoint follows Orb's + [standardized pagination format](/api-reference/pagination). + + Args: + cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned + from the initial request. + + customer_id: Fetch alerts scoped to this customer_id + + external_customer_id: Fetch alerts scoped to this external_customer_id + + limit: The number of items to fetch. Defaults to 20. + + subscription_id: Fetch alerts scoped to this subscription_id + + 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_api_list( + "/alerts", + page=AsyncPage[Alert], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "created_at_gt": created_at_gt, + "created_at_gte": created_at_gte, + "created_at_lt": created_at_lt, + "created_at_lte": created_at_lte, + "cursor": cursor, + "customer_id": customer_id, + "external_customer_id": external_customer_id, + "limit": limit, + "subscription_id": subscription_id, + }, + alert_list_params.AlertListParams, + ), + ), + model=Alert, + ) + + async def create_for_customer( + self, + customer_id: str, + *, + currency: str, + type: Literal["credit_balance_depleted", "credit_balance_dropped", "credit_balance_recovered"], + thresholds: Optional[Iterable[ThresholdParam]] | Omit = omit, + # 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, + ) -> Alert: + """This endpoint creates a new alert to monitor a customer's credit balance. + + There + are three types of alerts that can be scoped to customers: + `credit_balance_depleted`, `credit_balance_dropped`, and + `credit_balance_recovered`. Customers can have a maximum of one of each type of + alert per [credit balance currency](/product-catalog/prepurchase). + `credit_balance_dropped` alerts require a list of thresholds to be provided + while `credit_balance_depleted` and `credit_balance_recovered` alerts do not + require thresholds. + + Args: + currency: The case sensitive currency or custom pricing unit to use for this alert. + + type: The type of alert to create. This must be a valid alert type. + + thresholds: The thresholds that define the values at which the alert will be triggered. + + 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 customer_id: + raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") + return await self._post( + path_template("/alerts/customer_id/{customer_id}", customer_id=customer_id), + body=await async_maybe_transform( + { + "currency": currency, + "type": type, + "thresholds": thresholds, + }, + alert_create_for_customer_params.AlertCreateForCustomerParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Alert, + ) + + async def create_for_external_customer( + self, + external_customer_id: str, + *, + currency: str, + type: Literal["credit_balance_depleted", "credit_balance_dropped", "credit_balance_recovered"], + thresholds: Optional[Iterable[ThresholdParam]] | Omit = omit, + # 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, + ) -> Alert: + """This endpoint creates a new alert to monitor a customer's credit balance. + + There + are three types of alerts that can be scoped to customers: + `credit_balance_depleted`, `credit_balance_dropped`, and + `credit_balance_recovered`. Customers can have a maximum of one of each type of + alert per [credit balance currency](/product-catalog/prepurchase). + `credit_balance_dropped` alerts require a list of thresholds to be provided + while `credit_balance_depleted` and `credit_balance_recovered` alerts do not + require thresholds. + + Args: + currency: The case sensitive currency or custom pricing unit to use for this alert. + + type: The type of alert to create. This must be a valid alert type. + + thresholds: The thresholds that define the values at which the alert will be triggered. + + 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 external_customer_id: + raise ValueError( + f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" + ) + return await self._post( + path_template( + "/alerts/external_customer_id/{external_customer_id}", external_customer_id=external_customer_id + ), + body=await async_maybe_transform( + { + "currency": currency, + "type": type, + "thresholds": thresholds, + }, + alert_create_for_external_customer_params.AlertCreateForExternalCustomerParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Alert, + ) + + async def create_for_subscription( + self, + subscription_id: str, + *, + thresholds: Iterable[ThresholdParam], + type: Literal["usage_exceeded", "cost_exceeded"], + currency: Optional[str] | Omit = omit, + grouping_keys: Optional[SequenceNotStr[str]] | Omit = omit, + metric_id: Optional[str] | Omit = omit, + price_filters: Optional[Iterable[alert_create_for_subscription_params.PriceFilter]] | Omit = omit, + threshold_overrides: Optional[Iterable[alert_create_for_subscription_params.ThresholdOverride]] | Omit = omit, + # 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, + ) -> Alert: + """ + This endpoint is used to create alerts at the subscription level. + + Subscription level alerts can be one of two types: `usage_exceeded` or + `cost_exceeded`. A `usage_exceeded` alert is scoped to a particular metric and + is triggered when the usage of that metric exceeds predefined thresholds during + the current billing cycle. A `cost_exceeded` alert is triggered when the total + amount due during the current billing cycle surpasses predefined thresholds. + `cost_exceeded` alerts do not include burndown of pre-purchase credits. Each + subscription can have one `cost_exceeded` alert and one `usage_exceeded` alert + per metric that is a part of the subscription. Alerts are triggered based on + usage or cost conditions met during the current billing cycle. + + Args: + thresholds: The thresholds that define the values at which the alert will be triggered. + + type: The type of alert to create. This must be a valid alert type. + + currency: The case sensitive currency or custom pricing unit to use for grouped cost + alerts. Required when grouping_keys is set. + + grouping_keys: The property keys to group cost alerts by. Only applicable for cost_exceeded + alerts. + + metric_id: The metric to track usage for. + + price_filters: Filters to scope which prices are included in grouped cost alert evaluation. + Supports filtering by price_id, item_id, or price_type with includes/excludes + operators. Only applicable when grouping_keys is set. + + threshold_overrides: Per-group threshold overrides. Each override maps a specific combination of + grouping_keys values to a list of thresholds that fully replaces the default + thresholds for that group. An empty thresholds list silences the group. Groups + without an override use the default thresholds. Only applicable when + grouping_keys is set. + + 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( + path_template("/alerts/subscription_id/{subscription_id}", subscription_id=subscription_id), + body=await async_maybe_transform( + { + "thresholds": thresholds, + "type": type, + "currency": currency, + "grouping_keys": grouping_keys, + "metric_id": metric_id, + "price_filters": price_filters, + "threshold_overrides": threshold_overrides, + }, + alert_create_for_subscription_params.AlertCreateForSubscriptionParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Alert, + ) + + async def disable( + self, + alert_configuration_id: str, + *, + subscription_id: Optional[str] | Omit = omit, + # 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, + ) -> Alert: + """This endpoint allows you to disable an alert. + + To disable a plan-level alert for + a specific subscription, you must include the `subscription_id`. The + `subscription_id` is not required for customer or subscription level alerts. + + Args: + subscription_id: Used to update the status of a plan alert scoped to this subscription_id + + 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 alert_configuration_id: + raise ValueError( + f"Expected a non-empty value for `alert_configuration_id` but received {alert_configuration_id!r}" + ) + return await self._post( + path_template("/alerts/{alert_configuration_id}/disable", alert_configuration_id=alert_configuration_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + query=await async_maybe_transform( + {"subscription_id": subscription_id}, alert_disable_params.AlertDisableParams + ), + ), + cast_to=Alert, + ) + + async def enable( + self, + alert_configuration_id: str, + *, + subscription_id: Optional[str] | Omit = omit, + # 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, + ) -> Alert: + """This endpoint allows you to enable an alert. + + To enable a plan-level alert for a + specific subscription, you must include the `subscription_id`. The + `subscription_id` is not required for customer or subscription level alerts. + + Args: + subscription_id: Used to update the status of a plan alert scoped to this subscription_id + + 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 alert_configuration_id: + raise ValueError( + f"Expected a non-empty value for `alert_configuration_id` but received {alert_configuration_id!r}" + ) + return await self._post( + path_template("/alerts/{alert_configuration_id}/enable", alert_configuration_id=alert_configuration_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + query=await async_maybe_transform( + {"subscription_id": subscription_id}, alert_enable_params.AlertEnableParams + ), + ), + cast_to=Alert, + ) + + +class AlertsWithRawResponse: + def __init__(self, alerts: Alerts) -> None: + self._alerts = alerts + + self.retrieve = _legacy_response.to_raw_response_wrapper( + alerts.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + alerts.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + alerts.list, + ) + self.create_for_customer = _legacy_response.to_raw_response_wrapper( + alerts.create_for_customer, + ) + self.create_for_external_customer = _legacy_response.to_raw_response_wrapper( + alerts.create_for_external_customer, + ) + self.create_for_subscription = _legacy_response.to_raw_response_wrapper( + alerts.create_for_subscription, + ) + self.disable = _legacy_response.to_raw_response_wrapper( + alerts.disable, + ) + self.enable = _legacy_response.to_raw_response_wrapper( + alerts.enable, + ) + + +class AsyncAlertsWithRawResponse: + def __init__(self, alerts: AsyncAlerts) -> None: + self._alerts = alerts + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + alerts.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + alerts.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + alerts.list, + ) + self.create_for_customer = _legacy_response.async_to_raw_response_wrapper( + alerts.create_for_customer, + ) + self.create_for_external_customer = _legacy_response.async_to_raw_response_wrapper( + alerts.create_for_external_customer, + ) + self.create_for_subscription = _legacy_response.async_to_raw_response_wrapper( + alerts.create_for_subscription, + ) + self.disable = _legacy_response.async_to_raw_response_wrapper( + alerts.disable, + ) + self.enable = _legacy_response.async_to_raw_response_wrapper( + alerts.enable, + ) + + +class AlertsWithStreamingResponse: + def __init__(self, alerts: Alerts) -> None: + self._alerts = alerts + + self.retrieve = to_streamed_response_wrapper( + alerts.retrieve, + ) + self.update = to_streamed_response_wrapper( + alerts.update, + ) + self.list = to_streamed_response_wrapper( + alerts.list, + ) + self.create_for_customer = to_streamed_response_wrapper( + alerts.create_for_customer, + ) + self.create_for_external_customer = to_streamed_response_wrapper( + alerts.create_for_external_customer, + ) + self.create_for_subscription = to_streamed_response_wrapper( + alerts.create_for_subscription, + ) + self.disable = to_streamed_response_wrapper( + alerts.disable, + ) + self.enable = to_streamed_response_wrapper( + alerts.enable, + ) + + +class AsyncAlertsWithStreamingResponse: + def __init__(self, alerts: AsyncAlerts) -> None: + self._alerts = alerts + + self.retrieve = async_to_streamed_response_wrapper( + alerts.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + alerts.update, + ) + self.list = async_to_streamed_response_wrapper( + alerts.list, + ) + self.create_for_customer = async_to_streamed_response_wrapper( + alerts.create_for_customer, + ) + self.create_for_external_customer = async_to_streamed_response_wrapper( + alerts.create_for_external_customer, + ) + self.create_for_subscription = async_to_streamed_response_wrapper( + alerts.create_for_subscription, + ) + self.disable = async_to_streamed_response_wrapper( + alerts.disable, + ) + self.enable = async_to_streamed_response_wrapper( + alerts.enable, + ) diff --git a/src/orb/resources/beta/__init__.py b/src/orb/resources/beta/__init__.py index 1a5c5c8a..584deb5e 100644 --- a/src/orb/resources/beta/__init__.py +++ b/src/orb/resources/beta/__init__.py @@ -8,22 +8,22 @@ BetaWithStreamingResponse, AsyncBetaWithStreamingResponse, ) -from .price import ( - Price, - AsyncPrice, - PriceWithRawResponse, - AsyncPriceWithRawResponse, - PriceWithStreamingResponse, - AsyncPriceWithStreamingResponse, +from .external_plan_id import ( + ExternalPlanID, + AsyncExternalPlanID, + ExternalPlanIDWithRawResponse, + AsyncExternalPlanIDWithRawResponse, + ExternalPlanIDWithStreamingResponse, + AsyncExternalPlanIDWithStreamingResponse, ) __all__ = [ - "Price", - "AsyncPrice", - "PriceWithRawResponse", - "AsyncPriceWithRawResponse", - "PriceWithStreamingResponse", - "AsyncPriceWithStreamingResponse", + "ExternalPlanID", + "AsyncExternalPlanID", + "ExternalPlanIDWithRawResponse", + "AsyncExternalPlanIDWithRawResponse", + "ExternalPlanIDWithStreamingResponse", + "AsyncExternalPlanIDWithStreamingResponse", "Beta", "AsyncBeta", "BetaWithRawResponse", diff --git a/src/orb/resources/beta/beta.py b/src/orb/resources/beta/beta.py index 6c01e879..4a49637c 100644 --- a/src/orb/resources/beta/beta.py +++ b/src/orb/resources/beta/beta.py @@ -2,79 +2,517 @@ from __future__ import annotations -from .price import ( - Price, - AsyncPrice, - PriceWithRawResponse, - AsyncPriceWithRawResponse, - PriceWithStreamingResponse, - AsyncPriceWithStreamingResponse, -) +from typing import Iterable, Optional + +import httpx + +from ... import _legacy_response +from ...types import beta_create_plan_version_params, beta_set_default_plan_version_params +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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 ...types.plan import Plan +from ..._base_client import make_request_options +from .external_plan_id import ( + ExternalPlanID, + AsyncExternalPlanID, + ExternalPlanIDWithRawResponse, + AsyncExternalPlanIDWithRawResponse, + ExternalPlanIDWithStreamingResponse, + AsyncExternalPlanIDWithStreamingResponse, +) +from ...types.plan_version import PlanVersion __all__ = ["Beta", "AsyncBeta"] class Beta(SyncAPIResource): + """ + The [Plan](/core-concepts#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). + """ + @cached_property - def price(self) -> Price: - return Price(self._client) + def external_plan_id(self) -> ExternalPlanID: + """ + The [Plan](/core-concepts#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). + """ + return ExternalPlanID(self._client) @cached_property def with_raw_response(self) -> BetaWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 BetaWithRawResponse(self) @cached_property def with_streaming_response(self) -> BetaWithStreamingResponse: + """ + 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 BetaWithStreamingResponse(self) + def create_plan_version( + self, + plan_id: str, + *, + version: int, + add_adjustments: Optional[Iterable[beta_create_plan_version_params.AddAdjustment]] | Omit = omit, + add_prices: Optional[Iterable[beta_create_plan_version_params.AddPrice]] | Omit = omit, + remove_adjustments: Optional[Iterable[beta_create_plan_version_params.RemoveAdjustment]] | Omit = omit, + remove_prices: Optional[Iterable[beta_create_plan_version_params.RemovePrice]] | Omit = omit, + replace_adjustments: Optional[Iterable[beta_create_plan_version_params.ReplaceAdjustment]] | Omit = omit, + replace_prices: Optional[Iterable[beta_create_plan_version_params.ReplacePrice]] | Omit = omit, + set_as_default: Optional[bool] | Omit = omit, + # 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, + ) -> PlanVersion: + """ + This endpoint allows the creation of a new plan version for an existing plan. + + Args: + version: New version number. + + add_adjustments: Additional adjustments to be added to the plan. + + add_prices: Additional prices to be added to the plan. + + remove_adjustments: Adjustments to be removed from the plan. + + remove_prices: Prices to be removed from the plan. + + replace_adjustments: Adjustments to be replaced with additional adjustments on the plan. + + replace_prices: Prices to be replaced with additional prices on the plan. + + set_as_default: Set this new plan version as the default + + 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 plan_id: + raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") + return self._post( + path_template("/plans/{plan_id}/versions", plan_id=plan_id), + body=maybe_transform( + { + "version": version, + "add_adjustments": add_adjustments, + "add_prices": add_prices, + "remove_adjustments": remove_adjustments, + "remove_prices": remove_prices, + "replace_adjustments": replace_adjustments, + "replace_prices": replace_prices, + "set_as_default": set_as_default, + }, + beta_create_plan_version_params.BetaCreatePlanVersionParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=PlanVersion, + ) + + def fetch_plan_version( + self, + version: str, + *, + plan_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PlanVersion: + """This endpoint is used to fetch a plan version. + + It returns the phases, prices, + and adjustments present on this version of the plan. + + Args: + 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 + """ + if not plan_id: + raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") + if not version: + raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") + return self._get( + path_template("/plans/{plan_id}/versions/{version}", plan_id=plan_id, version=version), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PlanVersion, + ) + + def set_default_plan_version( + self, + plan_id: str, + *, + version: int, + # 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, + ) -> Plan: + """ + This endpoint allows setting the default version of a plan. + + Args: + version: Plan version to set as the default. + + 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 plan_id: + raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") + return self._post( + path_template("/plans/{plan_id}/set_default_version", plan_id=plan_id), + body=maybe_transform( + {"version": version}, beta_set_default_plan_version_params.BetaSetDefaultPlanVersionParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Plan, + ) + class AsyncBeta(AsyncAPIResource): + """ + The [Plan](/core-concepts#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). + """ + @cached_property - def price(self) -> AsyncPrice: - return AsyncPrice(self._client) + def external_plan_id(self) -> AsyncExternalPlanID: + """ + The [Plan](/core-concepts#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). + """ + return AsyncExternalPlanID(self._client) @cached_property def with_raw_response(self) -> AsyncBetaWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncBetaWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncBetaWithStreamingResponse: + """ + 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 AsyncBetaWithStreamingResponse(self) + async def create_plan_version( + self, + plan_id: str, + *, + version: int, + add_adjustments: Optional[Iterable[beta_create_plan_version_params.AddAdjustment]] | Omit = omit, + add_prices: Optional[Iterable[beta_create_plan_version_params.AddPrice]] | Omit = omit, + remove_adjustments: Optional[Iterable[beta_create_plan_version_params.RemoveAdjustment]] | Omit = omit, + remove_prices: Optional[Iterable[beta_create_plan_version_params.RemovePrice]] | Omit = omit, + replace_adjustments: Optional[Iterable[beta_create_plan_version_params.ReplaceAdjustment]] | Omit = omit, + replace_prices: Optional[Iterable[beta_create_plan_version_params.ReplacePrice]] | Omit = omit, + set_as_default: Optional[bool] | Omit = omit, + # 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, + ) -> PlanVersion: + """ + This endpoint allows the creation of a new plan version for an existing plan. + + Args: + version: New version number. + + add_adjustments: Additional adjustments to be added to the plan. + + add_prices: Additional prices to be added to the plan. + + remove_adjustments: Adjustments to be removed from the plan. + + remove_prices: Prices to be removed from the plan. + + replace_adjustments: Adjustments to be replaced with additional adjustments on the plan. + + replace_prices: Prices to be replaced with additional prices on the plan. + + set_as_default: Set this new plan version as the default + + 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 plan_id: + raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") + return await self._post( + path_template("/plans/{plan_id}/versions", plan_id=plan_id), + body=await async_maybe_transform( + { + "version": version, + "add_adjustments": add_adjustments, + "add_prices": add_prices, + "remove_adjustments": remove_adjustments, + "remove_prices": remove_prices, + "replace_adjustments": replace_adjustments, + "replace_prices": replace_prices, + "set_as_default": set_as_default, + }, + beta_create_plan_version_params.BetaCreatePlanVersionParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=PlanVersion, + ) + + async def fetch_plan_version( + self, + version: str, + *, + plan_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PlanVersion: + """This endpoint is used to fetch a plan version. + + It returns the phases, prices, + and adjustments present on this version of the plan. + + Args: + 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 + """ + if not plan_id: + raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") + if not version: + raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") + return await self._get( + path_template("/plans/{plan_id}/versions/{version}", plan_id=plan_id, version=version), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PlanVersion, + ) + + async def set_default_plan_version( + self, + plan_id: str, + *, + version: int, + # 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, + ) -> Plan: + """ + This endpoint allows setting the default version of a plan. + + Args: + version: Plan version to set as the default. + + 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 plan_id: + raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") + return await self._post( + path_template("/plans/{plan_id}/set_default_version", plan_id=plan_id), + body=await async_maybe_transform( + {"version": version}, beta_set_default_plan_version_params.BetaSetDefaultPlanVersionParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Plan, + ) + class BetaWithRawResponse: def __init__(self, beta: Beta) -> None: self._beta = beta + self.create_plan_version = _legacy_response.to_raw_response_wrapper( + beta.create_plan_version, + ) + self.fetch_plan_version = _legacy_response.to_raw_response_wrapper( + beta.fetch_plan_version, + ) + self.set_default_plan_version = _legacy_response.to_raw_response_wrapper( + beta.set_default_plan_version, + ) + @cached_property - def price(self) -> PriceWithRawResponse: - return PriceWithRawResponse(self._beta.price) + def external_plan_id(self) -> ExternalPlanIDWithRawResponse: + """ + The [Plan](/core-concepts#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). + """ + return ExternalPlanIDWithRawResponse(self._beta.external_plan_id) class AsyncBetaWithRawResponse: def __init__(self, beta: AsyncBeta) -> None: self._beta = beta + self.create_plan_version = _legacy_response.async_to_raw_response_wrapper( + beta.create_plan_version, + ) + self.fetch_plan_version = _legacy_response.async_to_raw_response_wrapper( + beta.fetch_plan_version, + ) + self.set_default_plan_version = _legacy_response.async_to_raw_response_wrapper( + beta.set_default_plan_version, + ) + @cached_property - def price(self) -> AsyncPriceWithRawResponse: - return AsyncPriceWithRawResponse(self._beta.price) + def external_plan_id(self) -> AsyncExternalPlanIDWithRawResponse: + """ + The [Plan](/core-concepts#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). + """ + return AsyncExternalPlanIDWithRawResponse(self._beta.external_plan_id) class BetaWithStreamingResponse: def __init__(self, beta: Beta) -> None: self._beta = beta + self.create_plan_version = to_streamed_response_wrapper( + beta.create_plan_version, + ) + self.fetch_plan_version = to_streamed_response_wrapper( + beta.fetch_plan_version, + ) + self.set_default_plan_version = to_streamed_response_wrapper( + beta.set_default_plan_version, + ) + @cached_property - def price(self) -> PriceWithStreamingResponse: - return PriceWithStreamingResponse(self._beta.price) + def external_plan_id(self) -> ExternalPlanIDWithStreamingResponse: + """ + The [Plan](/core-concepts#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). + """ + return ExternalPlanIDWithStreamingResponse(self._beta.external_plan_id) class AsyncBetaWithStreamingResponse: def __init__(self, beta: AsyncBeta) -> None: self._beta = beta + self.create_plan_version = async_to_streamed_response_wrapper( + beta.create_plan_version, + ) + self.fetch_plan_version = async_to_streamed_response_wrapper( + beta.fetch_plan_version, + ) + self.set_default_plan_version = async_to_streamed_response_wrapper( + beta.set_default_plan_version, + ) + @cached_property - def price(self) -> AsyncPriceWithStreamingResponse: - return AsyncPriceWithStreamingResponse(self._beta.price) + def external_plan_id(self) -> AsyncExternalPlanIDWithStreamingResponse: + """ + The [Plan](/core-concepts#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). + """ + return AsyncExternalPlanIDWithStreamingResponse(self._beta.external_plan_id) diff --git a/src/orb/resources/beta/external_plan_id.py b/src/orb/resources/beta/external_plan_id.py new file mode 100644 index 00000000..48aa0a7d --- /dev/null +++ b/src/orb/resources/beta/external_plan_id.py @@ -0,0 +1,474 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional + +import httpx + +from ... import _legacy_response +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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 ...types.beta import external_plan_id_create_plan_version_params, external_plan_id_set_default_plan_version_params +from ...types.plan import Plan +from ..._base_client import make_request_options +from ...types.plan_version import PlanVersion + +__all__ = ["ExternalPlanID", "AsyncExternalPlanID"] + + +class ExternalPlanID(SyncAPIResource): + """ + The [Plan](/core-concepts#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). + """ + + @cached_property + def with_raw_response(self) -> ExternalPlanIDWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 create_plan_version( + self, + external_plan_id: str, + *, + version: int, + add_adjustments: Optional[Iterable[external_plan_id_create_plan_version_params.AddAdjustment]] | Omit = omit, + add_prices: Optional[Iterable[external_plan_id_create_plan_version_params.AddPrice]] | Omit = omit, + remove_adjustments: Optional[Iterable[external_plan_id_create_plan_version_params.RemoveAdjustment]] + | Omit = omit, + remove_prices: Optional[Iterable[external_plan_id_create_plan_version_params.RemovePrice]] | Omit = omit, + replace_adjustments: Optional[Iterable[external_plan_id_create_plan_version_params.ReplaceAdjustment]] + | Omit = omit, + replace_prices: Optional[Iterable[external_plan_id_create_plan_version_params.ReplacePrice]] | Omit = omit, + set_as_default: Optional[bool] | Omit = omit, + # 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, + ) -> PlanVersion: + """ + This endpoint allows the creation of a new plan version for an existing plan. + + Args: + version: New version number. + + add_adjustments: Additional adjustments to be added to the plan. + + add_prices: Additional prices to be added to the plan. + + remove_adjustments: Adjustments to be removed from the plan. + + remove_prices: Prices to be removed from the plan. + + replace_adjustments: Adjustments to be replaced with additional adjustments on the plan. + + replace_prices: Prices to be replaced with additional prices on the plan. + + set_as_default: Set this new plan version as the default + + 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 external_plan_id: + raise ValueError(f"Expected a non-empty value for `external_plan_id` but received {external_plan_id!r}") + return self._post( + path_template("/plans/external_plan_id/{external_plan_id}/versions", external_plan_id=external_plan_id), + body=maybe_transform( + { + "version": version, + "add_adjustments": add_adjustments, + "add_prices": add_prices, + "remove_adjustments": remove_adjustments, + "remove_prices": remove_prices, + "replace_adjustments": replace_adjustments, + "replace_prices": replace_prices, + "set_as_default": set_as_default, + }, + external_plan_id_create_plan_version_params.ExternalPlanIDCreatePlanVersionParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=PlanVersion, + ) + + def fetch_plan_version( + self, + version: str, + *, + external_plan_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PlanVersion: + """This endpoint is used to fetch a plan version. + + It returns the phases, prices, + and adjustments present on this version of the plan. + + Args: + 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 + """ + if not external_plan_id: + raise ValueError(f"Expected a non-empty value for `external_plan_id` but received {external_plan_id!r}") + if not version: + raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") + return self._get( + path_template( + "/plans/external_plan_id/{external_plan_id}/versions/{version}", + external_plan_id=external_plan_id, + version=version, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PlanVersion, + ) + + def set_default_plan_version( + self, + external_plan_id: str, + *, + version: int, + # 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, + ) -> Plan: + """ + This endpoint allows setting the default version of a plan. + + Args: + version: Plan version to set as the default. + + 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 external_plan_id: + raise ValueError(f"Expected a non-empty value for `external_plan_id` but received {external_plan_id!r}") + return self._post( + path_template( + "/plans/external_plan_id/{external_plan_id}/set_default_version", external_plan_id=external_plan_id + ), + body=maybe_transform( + {"version": version}, + external_plan_id_set_default_plan_version_params.ExternalPlanIDSetDefaultPlanVersionParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Plan, + ) + + +class AsyncExternalPlanID(AsyncAPIResource): + """ + The [Plan](/core-concepts#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). + """ + + @cached_property + def with_raw_response(self) -> AsyncExternalPlanIDWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 create_plan_version( + self, + external_plan_id: str, + *, + version: int, + add_adjustments: Optional[Iterable[external_plan_id_create_plan_version_params.AddAdjustment]] | Omit = omit, + add_prices: Optional[Iterable[external_plan_id_create_plan_version_params.AddPrice]] | Omit = omit, + remove_adjustments: Optional[Iterable[external_plan_id_create_plan_version_params.RemoveAdjustment]] + | Omit = omit, + remove_prices: Optional[Iterable[external_plan_id_create_plan_version_params.RemovePrice]] | Omit = omit, + replace_adjustments: Optional[Iterable[external_plan_id_create_plan_version_params.ReplaceAdjustment]] + | Omit = omit, + replace_prices: Optional[Iterable[external_plan_id_create_plan_version_params.ReplacePrice]] | Omit = omit, + set_as_default: Optional[bool] | Omit = omit, + # 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, + ) -> PlanVersion: + """ + This endpoint allows the creation of a new plan version for an existing plan. + + Args: + version: New version number. + + add_adjustments: Additional adjustments to be added to the plan. + + add_prices: Additional prices to be added to the plan. + + remove_adjustments: Adjustments to be removed from the plan. + + remove_prices: Prices to be removed from the plan. + + replace_adjustments: Adjustments to be replaced with additional adjustments on the plan. + + replace_prices: Prices to be replaced with additional prices on the plan. + + set_as_default: Set this new plan version as the default + + 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 external_plan_id: + raise ValueError(f"Expected a non-empty value for `external_plan_id` but received {external_plan_id!r}") + return await self._post( + path_template("/plans/external_plan_id/{external_plan_id}/versions", external_plan_id=external_plan_id), + body=await async_maybe_transform( + { + "version": version, + "add_adjustments": add_adjustments, + "add_prices": add_prices, + "remove_adjustments": remove_adjustments, + "remove_prices": remove_prices, + "replace_adjustments": replace_adjustments, + "replace_prices": replace_prices, + "set_as_default": set_as_default, + }, + external_plan_id_create_plan_version_params.ExternalPlanIDCreatePlanVersionParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=PlanVersion, + ) + + async def fetch_plan_version( + self, + version: str, + *, + external_plan_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PlanVersion: + """This endpoint is used to fetch a plan version. + + It returns the phases, prices, + and adjustments present on this version of the plan. + + Args: + 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 + """ + if not external_plan_id: + raise ValueError(f"Expected a non-empty value for `external_plan_id` but received {external_plan_id!r}") + if not version: + raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") + return await self._get( + path_template( + "/plans/external_plan_id/{external_plan_id}/versions/{version}", + external_plan_id=external_plan_id, + version=version, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PlanVersion, + ) + + async def set_default_plan_version( + self, + external_plan_id: str, + *, + version: int, + # 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, + ) -> Plan: + """ + This endpoint allows setting the default version of a plan. + + Args: + version: Plan version to set as the default. + + 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 external_plan_id: + raise ValueError(f"Expected a non-empty value for `external_plan_id` but received {external_plan_id!r}") + return await self._post( + path_template( + "/plans/external_plan_id/{external_plan_id}/set_default_version", external_plan_id=external_plan_id + ), + body=await async_maybe_transform( + {"version": version}, + external_plan_id_set_default_plan_version_params.ExternalPlanIDSetDefaultPlanVersionParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Plan, + ) + + +class ExternalPlanIDWithRawResponse: + def __init__(self, external_plan_id: ExternalPlanID) -> None: + self._external_plan_id = external_plan_id + + self.create_plan_version = _legacy_response.to_raw_response_wrapper( + external_plan_id.create_plan_version, + ) + self.fetch_plan_version = _legacy_response.to_raw_response_wrapper( + external_plan_id.fetch_plan_version, + ) + self.set_default_plan_version = _legacy_response.to_raw_response_wrapper( + external_plan_id.set_default_plan_version, + ) + + +class AsyncExternalPlanIDWithRawResponse: + def __init__(self, external_plan_id: AsyncExternalPlanID) -> None: + self._external_plan_id = external_plan_id + + self.create_plan_version = _legacy_response.async_to_raw_response_wrapper( + external_plan_id.create_plan_version, + ) + self.fetch_plan_version = _legacy_response.async_to_raw_response_wrapper( + external_plan_id.fetch_plan_version, + ) + self.set_default_plan_version = _legacy_response.async_to_raw_response_wrapper( + external_plan_id.set_default_plan_version, + ) + + +class ExternalPlanIDWithStreamingResponse: + def __init__(self, external_plan_id: ExternalPlanID) -> None: + self._external_plan_id = external_plan_id + + self.create_plan_version = to_streamed_response_wrapper( + external_plan_id.create_plan_version, + ) + self.fetch_plan_version = to_streamed_response_wrapper( + external_plan_id.fetch_plan_version, + ) + self.set_default_plan_version = to_streamed_response_wrapper( + external_plan_id.set_default_plan_version, + ) + + +class AsyncExternalPlanIDWithStreamingResponse: + def __init__(self, external_plan_id: AsyncExternalPlanID) -> None: + self._external_plan_id = external_plan_id + + self.create_plan_version = async_to_streamed_response_wrapper( + external_plan_id.create_plan_version, + ) + self.fetch_plan_version = async_to_streamed_response_wrapper( + external_plan_id.fetch_plan_version, + ) + self.set_default_plan_version = async_to_streamed_response_wrapper( + external_plan_id.set_default_plan_version, + ) diff --git a/src/orb/resources/beta/price.py b/src/orb/resources/beta/price.py deleted file mode 100644 index c0f347c0..00000000 --- a/src/orb/resources/beta/price.py +++ /dev/null @@ -1,266 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, 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 ...types.beta import PriceEvaluateResponse, price_evaluate_params -from ..._base_client import ( - make_request_options, -) - -__all__ = ["Price", "AsyncPrice"] - - -class Price(SyncAPIResource): - @cached_property - def with_raw_response(self) -> PriceWithRawResponse: - return PriceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> PriceWithStreamingResponse: - return PriceWithStreamingResponse(self) - - def evaluate( - self, - price_id: str, - *, - timeframe_end: Union[str, datetime], - timeframe_start: Union[str, datetime], - customer_id: Optional[str] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - filter: Optional[str] | NotGiven = NOT_GIVEN, - grouping_keys: List[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, - ) -> PriceEvaluateResponse: - """ - This endpoint is used to evaluate the output of a price for a given customer and - time range. It enables filtering and grouping the output using - [computed properties](../guides/extensibility/advanced-metrics#computed-properties), - supporting the following workflows: - - 1. Showing detailed usage and costs to the end customer. - 2. Auditing subtotals on invoice line items. - - For these workflows, the expressiveness of computed properties in both the - filters and grouping is critical. For example, if you'd like to show your - customer their usage grouped by hour and another property, you can do so with - the following `grouping_keys`: - `["hour_floor_timestamp_millis(timestamp_millis)", "my_property"]`. If you'd - like to examine a customer's usage for a specific property value, you can do so - with the following `filter`: - `my_property = 'foo' AND my_other_property = 'bar'`. - - By default, the start of the time range must be no more than 100 days ago and - the length of the results must be no greater than 1000. Note that this is a POST - endpoint rather than a GET endpoint because it employs a JSON body rather than - query parameters. - - Args: - timeframe_end: The exclusive upper bound for event timestamps - - timeframe_start: The inclusive lower bound for event timestamps - - customer_id: The ID of the customer to which this evaluation is scoped. - - external_customer_id: The external customer ID of the customer to which this evaluation is scoped. - - filter: A boolean - [computed property](../guides/extensibility/advanced-metrics#computed-properties) - used to filter the underlying billable metric - - grouping_keys: Properties (or - [computed properties](../guides/extensibility/advanced-metrics#computed-properties)) - used to group the underlying billable metric - - 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 price_id: - raise ValueError(f"Expected a non-empty value for `price_id` but received {price_id!r}") - return self._post( - f"/prices/{price_id}/evaluate", - body=maybe_transform( - { - "timeframe_end": timeframe_end, - "timeframe_start": timeframe_start, - "customer_id": customer_id, - "external_customer_id": external_customer_id, - "filter": filter, - "grouping_keys": grouping_keys, - }, - price_evaluate_params.PriceEvaluateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - ), - cast_to=PriceEvaluateResponse, - ) - - -class AsyncPrice(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncPriceWithRawResponse: - return AsyncPriceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncPriceWithStreamingResponse: - return AsyncPriceWithStreamingResponse(self) - - async def evaluate( - self, - price_id: str, - *, - timeframe_end: Union[str, datetime], - timeframe_start: Union[str, datetime], - customer_id: Optional[str] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - filter: Optional[str] | NotGiven = NOT_GIVEN, - grouping_keys: List[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, - ) -> PriceEvaluateResponse: - """ - This endpoint is used to evaluate the output of a price for a given customer and - time range. It enables filtering and grouping the output using - [computed properties](../guides/extensibility/advanced-metrics#computed-properties), - supporting the following workflows: - - 1. Showing detailed usage and costs to the end customer. - 2. Auditing subtotals on invoice line items. - - For these workflows, the expressiveness of computed properties in both the - filters and grouping is critical. For example, if you'd like to show your - customer their usage grouped by hour and another property, you can do so with - the following `grouping_keys`: - `["hour_floor_timestamp_millis(timestamp_millis)", "my_property"]`. If you'd - like to examine a customer's usage for a specific property value, you can do so - with the following `filter`: - `my_property = 'foo' AND my_other_property = 'bar'`. - - By default, the start of the time range must be no more than 100 days ago and - the length of the results must be no greater than 1000. Note that this is a POST - endpoint rather than a GET endpoint because it employs a JSON body rather than - query parameters. - - Args: - timeframe_end: The exclusive upper bound for event timestamps - - timeframe_start: The inclusive lower bound for event timestamps - - customer_id: The ID of the customer to which this evaluation is scoped. - - external_customer_id: The external customer ID of the customer to which this evaluation is scoped. - - filter: A boolean - [computed property](../guides/extensibility/advanced-metrics#computed-properties) - used to filter the underlying billable metric - - grouping_keys: Properties (or - [computed properties](../guides/extensibility/advanced-metrics#computed-properties)) - used to group the underlying billable metric - - 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 price_id: - raise ValueError(f"Expected a non-empty value for `price_id` but received {price_id!r}") - return await self._post( - f"/prices/{price_id}/evaluate", - body=await async_maybe_transform( - { - "timeframe_end": timeframe_end, - "timeframe_start": timeframe_start, - "customer_id": customer_id, - "external_customer_id": external_customer_id, - "filter": filter, - "grouping_keys": grouping_keys, - }, - price_evaluate_params.PriceEvaluateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - ), - cast_to=PriceEvaluateResponse, - ) - - -class PriceWithRawResponse: - def __init__(self, price: Price) -> None: - self._price = price - - self.evaluate = _legacy_response.to_raw_response_wrapper( - price.evaluate, - ) - - -class AsyncPriceWithRawResponse: - def __init__(self, price: AsyncPrice) -> None: - self._price = price - - self.evaluate = _legacy_response.async_to_raw_response_wrapper( - price.evaluate, - ) - - -class PriceWithStreamingResponse: - def __init__(self, price: Price) -> None: - self._price = price - - self.evaluate = to_streamed_response_wrapper( - price.evaluate, - ) - - -class AsyncPriceWithStreamingResponse: - def __init__(self, price: AsyncPrice) -> None: - self._price = price - - self.evaluate = async_to_streamed_response_wrapper( - price.evaluate, - ) diff --git a/src/orb/resources/coupons/coupons.py b/src/orb/resources/coupons/coupons.py index e463a66d..7b3a9dad 100644 --- a/src/orb/resources/coupons/coupons.py +++ b/src/orb/resources/coupons/coupons.py @@ -7,12 +7,9 @@ import httpx from ... import _legacy_response -from ...types import Coupon, coupon_list_params, coupon_create_params -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import ( - maybe_transform, - async_maybe_transform, -) +from ...types import coupon_list_params, coupon_create_params +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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 @@ -25,25 +22,41 @@ SubscriptionsWithStreamingResponse, AsyncSubscriptionsWithStreamingResponse, ) -from ..._base_client import ( - AsyncPaginator, - make_request_options, -) +from ..._base_client import AsyncPaginator, make_request_options +from ...types.coupon import Coupon __all__ = ["Coupons", "AsyncCoupons"] class Coupons(SyncAPIResource): + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ + @cached_property def subscriptions(self) -> Subscriptions: + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ return Subscriptions(self._client) @cached_property def with_raw_response(self) -> CouponsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -51,14 +64,14 @@ def create( *, discount: coupon_create_params.Discount, redemption_code: str, - duration_in_months: Optional[int] | NotGiven = NOT_GIVEN, - max_redemptions: Optional[int] | NotGiven = NOT_GIVEN, + duration_in_months: Optional[int] | Omit = omit, + max_redemptions: Optional[int] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Coupon: """ @@ -108,24 +121,23 @@ def create( def list( self, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - redemption_code: Optional[str] | NotGiven = NOT_GIVEN, - show_archived: Optional[bool] | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + redemption_code: Optional[str] | Omit = omit, + show_archived: Optional[bool] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[Coupon]: """ This endpoint returns a list of all coupons for an account in a list format. The list of coupons is ordered starting from the most recently created coupon. The response also includes `pagination_metadata`, which lets the caller retrieve - the next page of results if they exist. More information about pagination can be - found in the Pagination-metadata schema. + the next page of results if they exist. Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -176,7 +188,7 @@ def archive( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Coupon: """This endpoint allows a coupon to be archived. @@ -199,7 +211,7 @@ def archive( if not coupon_id: raise ValueError(f"Expected a non-empty value for `coupon_id` but received {coupon_id!r}") return self._post( - f"/coupons/{coupon_id}/archive", + path_template("/coupons/{coupon_id}/archive", coupon_id=coupon_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -219,7 +231,7 @@ def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Coupon: """This endpoint retrieves a coupon by its ID. @@ -239,7 +251,7 @@ def fetch( if not coupon_id: raise ValueError(f"Expected a non-empty value for `coupon_id` but received {coupon_id!r}") return self._get( - f"/coupons/{coupon_id}", + path_template("/coupons/{coupon_id}", coupon_id=coupon_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -248,16 +260,34 @@ def fetch( class AsyncCoupons(AsyncAPIResource): + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ + @cached_property def subscriptions(self) -> AsyncSubscriptions: + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ return AsyncSubscriptions(self._client) @cached_property def with_raw_response(self) -> AsyncCouponsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -265,14 +295,14 @@ async def create( *, discount: coupon_create_params.Discount, redemption_code: str, - duration_in_months: Optional[int] | NotGiven = NOT_GIVEN, - max_redemptions: Optional[int] | NotGiven = NOT_GIVEN, + duration_in_months: Optional[int] | Omit = omit, + max_redemptions: Optional[int] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Coupon: """ @@ -322,24 +352,23 @@ async def create( def list( self, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - redemption_code: Optional[str] | NotGiven = NOT_GIVEN, - show_archived: Optional[bool] | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + redemption_code: Optional[str] | Omit = omit, + show_archived: Optional[bool] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Coupon, AsyncPage[Coupon]]: """ This endpoint returns a list of all coupons for an account in a list format. The list of coupons is ordered starting from the most recently created coupon. The response also includes `pagination_metadata`, which lets the caller retrieve - the next page of results if they exist. More information about pagination can be - found in the Pagination-metadata schema. + the next page of results if they exist. Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -390,7 +419,7 @@ async def archive( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Coupon: """This endpoint allows a coupon to be archived. @@ -413,7 +442,7 @@ async def archive( if not coupon_id: raise ValueError(f"Expected a non-empty value for `coupon_id` but received {coupon_id!r}") return await self._post( - f"/coupons/{coupon_id}/archive", + path_template("/coupons/{coupon_id}/archive", coupon_id=coupon_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -433,7 +462,7 @@ async def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Coupon: """This endpoint retrieves a coupon by its ID. @@ -453,7 +482,7 @@ async def fetch( if not coupon_id: raise ValueError(f"Expected a non-empty value for `coupon_id` but received {coupon_id!r}") return await self._get( - f"/coupons/{coupon_id}", + path_template("/coupons/{coupon_id}", coupon_id=coupon_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -480,6 +509,9 @@ def __init__(self, coupons: Coupons) -> None: @cached_property def subscriptions(self) -> SubscriptionsWithRawResponse: + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ return SubscriptionsWithRawResponse(self._coupons.subscriptions) @@ -502,6 +534,9 @@ def __init__(self, coupons: AsyncCoupons) -> None: @cached_property def subscriptions(self) -> AsyncSubscriptionsWithRawResponse: + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ return AsyncSubscriptionsWithRawResponse(self._coupons.subscriptions) @@ -524,6 +559,9 @@ def __init__(self, coupons: Coupons) -> None: @cached_property def subscriptions(self) -> SubscriptionsWithStreamingResponse: + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ return SubscriptionsWithStreamingResponse(self._coupons.subscriptions) @@ -546,4 +584,7 @@ def __init__(self, coupons: AsyncCoupons) -> None: @cached_property def subscriptions(self) -> AsyncSubscriptionsWithStreamingResponse: + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ return AsyncSubscriptionsWithStreamingResponse(self._coupons.subscriptions) diff --git a/src/orb/resources/coupons/subscriptions.py b/src/orb/resources/coupons/subscriptions.py index c93924ed..b8ea4181 100644 --- a/src/orb/resources/coupons/subscriptions.py +++ b/src/orb/resources/coupons/subscriptions.py @@ -7,49 +7,61 @@ import httpx from ... import _legacy_response -from ...types import Subscription -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import maybe_transform +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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 ...pagination import SyncPage, AsyncPage -from ..._base_client import ( - AsyncPaginator, - make_request_options, -) +from ..._base_client import AsyncPaginator, make_request_options from ...types.coupons import subscription_list_params +from ...types.subscription import Subscription __all__ = ["Subscriptions", "AsyncSubscriptions"] class Subscriptions(SyncAPIResource): + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ + @cached_property def with_raw_response(self) -> SubscriptionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( self, coupon_id: str, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[Subscription]: """ This endpoint returns a list of all subscriptions that have redeemed a given - coupon as a [paginated](../reference/pagination) list, ordered starting from the - most recently created subscription. For a full discussion of the subscription - resource, see [Subscription](../guides/concepts#subscription). + coupon as a [paginated](/api-reference/pagination) list, ordered starting from + the most recently created subscription. For a full discussion of the + subscription resource, see [Subscription](/core-concepts#subscription). Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -68,7 +80,7 @@ def list( if not coupon_id: raise ValueError(f"Expected a non-empty value for `coupon_id` but received {coupon_id!r}") return self._get_api_list( - f"/coupons/{coupon_id}/subscriptions", + path_template("/coupons/{coupon_id}/subscriptions", coupon_id=coupon_id), page=SyncPage[Subscription], options=make_request_options( extra_headers=extra_headers, @@ -88,32 +100,47 @@ def list( class AsyncSubscriptions(AsyncAPIResource): + """ + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. + """ + @cached_property def with_raw_response(self) -> AsyncSubscriptionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( self, coupon_id: str, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Subscription, AsyncPage[Subscription]]: """ This endpoint returns a list of all subscriptions that have redeemed a given - coupon as a [paginated](../reference/pagination) list, ordered starting from the - most recently created subscription. For a full discussion of the subscription - resource, see [Subscription](../guides/concepts#subscription). + coupon as a [paginated](/api-reference/pagination) list, ordered starting from + the most recently created subscription. For a full discussion of the + subscription resource, see [Subscription](/core-concepts#subscription). Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -132,7 +159,7 @@ def list( if not coupon_id: raise ValueError(f"Expected a non-empty value for `coupon_id` but received {coupon_id!r}") return self._get_api_list( - f"/coupons/{coupon_id}/subscriptions", + path_template("/coupons/{coupon_id}/subscriptions", coupon_id=coupon_id), page=AsyncPage[Subscription], options=make_request_options( extra_headers=extra_headers, diff --git a/src/orb/resources/credit_blocks.py b/src/orb/resources/credit_blocks.py new file mode 100644 index 00000000..8e30f760 --- /dev/null +++ b/src/orb/resources/credit_blocks.py @@ -0,0 +1,401 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .. import _legacy_response +from .._types import Body, Query, Headers, NoneType, NotGiven, not_given +from .._utils import path_template +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.credit_block_retrieve_response import CreditBlockRetrieveResponse +from ..types.credit_block_list_invoices_response import CreditBlockListInvoicesResponse + +__all__ = ["CreditBlocks", "AsyncCreditBlocks"] + + +class CreditBlocks(SyncAPIResource): + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ + + @cached_property + def with_raw_response(self) -> CreditBlocksWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 CreditBlocksWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CreditBlocksWithStreamingResponse: + """ + 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 CreditBlocksWithStreamingResponse(self) + + def retrieve( + self, + block_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CreditBlockRetrieveResponse: + """ + This endpoint returns a credit block identified by its block_id. + + Args: + 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 + """ + if not block_id: + raise ValueError(f"Expected a non-empty value for `block_id` but received {block_id!r}") + return self._get( + path_template("/credit_blocks/{block_id}", block_id=block_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CreditBlockRetrieveResponse, + ) + + def delete( + self, + block_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> None: + """ + This endpoint deletes a credit block by its ID. + + When a credit block is deleted: + + - The block is removed from the customer's credit ledger. + - Any usage of the credit block is reversed, and the ledger is replayed as if + the block never existed. + - If invoices were generated from the purchase of the credit block, they will be + deleted if in draft status, voided if issued, or a credit note will be issued + if the invoice is paid. + + + Issued invoices that had credits applied from this block will not be regenerated, but the ledger will + reflect the state as if credits from the deleted block were never applied. + + + Args: + 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 block_id: + raise ValueError(f"Expected a non-empty value for `block_id` but received {block_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template("/credit_blocks/{block_id}", block_id=block_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=NoneType, + ) + + def list_invoices( + self, + block_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CreditBlockListInvoicesResponse: + """ + This endpoint returns the credit block and its associated purchasing invoices. + + If a credit block was purchased (as opposed to being manually added), this + endpoint returns the invoices that were created to charge the customer for the + credit block. For credit blocks with payment schedules spanning multiple periods + (e.g., monthly payments over 12 months), multiple invoices will be returned. + + For credit blocks created by subscription allocation prices, this endpoint + returns the subscription invoice containing the allocation line item that + created the block. + + If the credit block was not purchased (e.g., manual increment), an empty + invoices list is returned. + + **Note: This endpoint is currently experimental and its interface may change in + future releases. Please contact support before building production integrations + against this endpoint.** + + Args: + 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 + """ + if not block_id: + raise ValueError(f"Expected a non-empty value for `block_id` but received {block_id!r}") + return self._get( + path_template("/credit_blocks/{block_id}/invoices", block_id=block_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CreditBlockListInvoicesResponse, + ) + + +class AsyncCreditBlocks(AsyncAPIResource): + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ + + @cached_property + def with_raw_response(self) -> AsyncCreditBlocksWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncCreditBlocksWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCreditBlocksWithStreamingResponse: + """ + 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 AsyncCreditBlocksWithStreamingResponse(self) + + async def retrieve( + self, + block_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CreditBlockRetrieveResponse: + """ + This endpoint returns a credit block identified by its block_id. + + Args: + 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 + """ + if not block_id: + raise ValueError(f"Expected a non-empty value for `block_id` but received {block_id!r}") + return await self._get( + path_template("/credit_blocks/{block_id}", block_id=block_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CreditBlockRetrieveResponse, + ) + + async def delete( + self, + block_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> None: + """ + This endpoint deletes a credit block by its ID. + + When a credit block is deleted: + + - The block is removed from the customer's credit ledger. + - Any usage of the credit block is reversed, and the ledger is replayed as if + the block never existed. + - If invoices were generated from the purchase of the credit block, they will be + deleted if in draft status, voided if issued, or a credit note will be issued + if the invoice is paid. + + + Issued invoices that had credits applied from this block will not be regenerated, but the ledger will + reflect the state as if credits from the deleted block were never applied. + + + Args: + 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 block_id: + raise ValueError(f"Expected a non-empty value for `block_id` but received {block_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template("/credit_blocks/{block_id}", block_id=block_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=NoneType, + ) + + async def list_invoices( + self, + block_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CreditBlockListInvoicesResponse: + """ + This endpoint returns the credit block and its associated purchasing invoices. + + If a credit block was purchased (as opposed to being manually added), this + endpoint returns the invoices that were created to charge the customer for the + credit block. For credit blocks with payment schedules spanning multiple periods + (e.g., monthly payments over 12 months), multiple invoices will be returned. + + For credit blocks created by subscription allocation prices, this endpoint + returns the subscription invoice containing the allocation line item that + created the block. + + If the credit block was not purchased (e.g., manual increment), an empty + invoices list is returned. + + **Note: This endpoint is currently experimental and its interface may change in + future releases. Please contact support before building production integrations + against this endpoint.** + + Args: + 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 + """ + if not block_id: + raise ValueError(f"Expected a non-empty value for `block_id` but received {block_id!r}") + return await self._get( + path_template("/credit_blocks/{block_id}/invoices", block_id=block_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CreditBlockListInvoicesResponse, + ) + + +class CreditBlocksWithRawResponse: + def __init__(self, credit_blocks: CreditBlocks) -> None: + self._credit_blocks = credit_blocks + + self.retrieve = _legacy_response.to_raw_response_wrapper( + credit_blocks.retrieve, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + credit_blocks.delete, + ) + self.list_invoices = _legacy_response.to_raw_response_wrapper( + credit_blocks.list_invoices, + ) + + +class AsyncCreditBlocksWithRawResponse: + def __init__(self, credit_blocks: AsyncCreditBlocks) -> None: + self._credit_blocks = credit_blocks + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + credit_blocks.retrieve, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + credit_blocks.delete, + ) + self.list_invoices = _legacy_response.async_to_raw_response_wrapper( + credit_blocks.list_invoices, + ) + + +class CreditBlocksWithStreamingResponse: + def __init__(self, credit_blocks: CreditBlocks) -> None: + self._credit_blocks = credit_blocks + + self.retrieve = to_streamed_response_wrapper( + credit_blocks.retrieve, + ) + self.delete = to_streamed_response_wrapper( + credit_blocks.delete, + ) + self.list_invoices = to_streamed_response_wrapper( + credit_blocks.list_invoices, + ) + + +class AsyncCreditBlocksWithStreamingResponse: + def __init__(self, credit_blocks: AsyncCreditBlocks) -> None: + self._credit_blocks = credit_blocks + + self.retrieve = async_to_streamed_response_wrapper( + credit_blocks.retrieve, + ) + self.delete = async_to_streamed_response_wrapper( + credit_blocks.delete, + ) + self.list_invoices = async_to_streamed_response_wrapper( + credit_blocks.list_invoices, + ) diff --git a/src/orb/resources/credit_notes.py b/src/orb/resources/credit_notes.py index 2e25e6f1..98307829 100644 --- a/src/orb/resources/credit_notes.py +++ b/src/orb/resources/credit_notes.py @@ -2,46 +2,158 @@ from __future__ import annotations -from typing import Optional +from typing import Union, Iterable, Optional +from datetime import date, datetime +from typing_extensions import Literal import httpx from .. import _legacy_response -from ..types import CreditNote, credit_note_list_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import maybe_transform +from ..types import credit_note_list_params, credit_note_create_params +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import path_template, 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 ..pagination import SyncPage, AsyncPage -from .._base_client import ( - AsyncPaginator, - make_request_options, -) +from .._base_client import AsyncPaginator, make_request_options +from ..types.shared.credit_note import CreditNote __all__ = ["CreditNotes", "AsyncCreditNotes"] class CreditNotes(SyncAPIResource): + """ + The [Credit Note](/invoicing/credit-notes) resource represents a credit that has been applied to a + particular invoice. + """ + @cached_property def with_raw_response(self) -> CreditNotesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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], + reason: Literal["duplicate", "fraudulent", "order_change", "product_unsatisfactory"], + end_date: Union[str, date, None] | Omit = omit, + memo: Optional[str] | Omit = omit, + start_date: Union[str, date, None] | Omit = omit, + # 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`](/invoicing/credit-notes). + + The credit note service period configuration supports two explicit modes: + + 1. Global service periods: Specify start_date and end_date at the credit note + level. These dates will be applied to all line items uniformly. + + 2. Individual service periods: Specify start_date and end_date for each line + item. When using this mode, ALL line items must have individual periods + specified. + + 3. Default behavior: If no service periods are specified (neither global nor + individual), the original invoice line item service periods will be used. + + Note: Mixing global and individual service periods in the same request is not + allowed to prevent confusion. + + Service period dates are normalized to the start of the day in the customer's + timezone to ensure consistent handling across different timezones. + + Date Format: Use start_date and end_date with format "YYYY-MM-DD" (e.g., + "2023-09-22") to match other Orb APIs like /v1/invoice_line_items. + + Note: Both start_date and end_date are inclusive - the service period will cover + both the start date and end date completely (from start of start_date to end of + end_date). + + Args: + reason: An optional reason for the credit note. + + end_date: A date string to specify the global credit note service period end date in the + customer's timezone. This will be applied to all line items that don't have + their own individual service periods specified. If not provided, line items will + use their original invoice line item service periods. This date is inclusive. + + memo: An optional memo to attach to the credit note. + + start_date: A date string to specify the global credit note service period start date in the + customer's timezone. This will be applied to all line items that don't have + their own individual service periods specified. If not provided, line items will + use their original invoice line item service periods. This date is inclusive. + + 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, + "reason": reason, + "end_date": end_date, + "memo": memo, + "start_date": start_date, + }, + 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, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[CreditNote]: """Get a paginated list of CreditNotes. @@ -73,6 +185,10 @@ def list( timeout=timeout, query=maybe_transform( { + "created_at_gt": created_at_gt, + "created_at_gte": created_at_gte, + "created_at_lt": created_at_lt, + "created_at_lte": created_at_lte, "cursor": cursor, "limit": limit, }, @@ -91,11 +207,11 @@ def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CreditNote: """ - This endpoint is used to fetch a single - [`Credit Note`](../guides/invoicing/credit-notes) given an identifier. + This endpoint is used to fetch a single [`Credit Note`](/invoicing/credit-notes) + given an identifier. Args: extra_headers: Send extra headers @@ -109,7 +225,7 @@ def fetch( if not credit_note_id: raise ValueError(f"Expected a non-empty value for `credit_note_id` but received {credit_note_id!r}") return self._get( - f"/credit_notes/{credit_note_id}", + path_template("/credit_notes/{credit_note_id}", credit_note_id=credit_note_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -118,25 +234,137 @@ def fetch( class AsyncCreditNotes(AsyncAPIResource): + """ + The [Credit Note](/invoicing/credit-notes) resource represents a credit that has been applied to a + particular invoice. + """ + @cached_property def with_raw_response(self) -> AsyncCreditNotesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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], + reason: Literal["duplicate", "fraudulent", "order_change", "product_unsatisfactory"], + end_date: Union[str, date, None] | Omit = omit, + memo: Optional[str] | Omit = omit, + start_date: Union[str, date, None] | Omit = omit, + # 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`](/invoicing/credit-notes). + + The credit note service period configuration supports two explicit modes: + + 1. Global service periods: Specify start_date and end_date at the credit note + level. These dates will be applied to all line items uniformly. + + 2. Individual service periods: Specify start_date and end_date for each line + item. When using this mode, ALL line items must have individual periods + specified. + + 3. Default behavior: If no service periods are specified (neither global nor + individual), the original invoice line item service periods will be used. + + Note: Mixing global and individual service periods in the same request is not + allowed to prevent confusion. + + Service period dates are normalized to the start of the day in the customer's + timezone to ensure consistent handling across different timezones. + + Date Format: Use start_date and end_date with format "YYYY-MM-DD" (e.g., + "2023-09-22") to match other Orb APIs like /v1/invoice_line_items. + + Note: Both start_date and end_date are inclusive - the service period will cover + both the start date and end date completely (from start of start_date to end of + end_date). + + Args: + reason: An optional reason for the credit note. + + end_date: A date string to specify the global credit note service period end date in the + customer's timezone. This will be applied to all line items that don't have + their own individual service periods specified. If not provided, line items will + use their original invoice line item service periods. This date is inclusive. + + memo: An optional memo to attach to the credit note. + + start_date: A date string to specify the global credit note service period start date in the + customer's timezone. This will be applied to all line items that don't have + their own individual service periods specified. If not provided, line items will + use their original invoice line item service periods. This date is inclusive. + + 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, + "reason": reason, + "end_date": end_date, + "memo": memo, + "start_date": start_date, + }, + 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, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[CreditNote, AsyncPage[CreditNote]]: """Get a paginated list of CreditNotes. @@ -168,6 +396,10 @@ def list( timeout=timeout, query=maybe_transform( { + "created_at_gt": created_at_gt, + "created_at_gte": created_at_gte, + "created_at_lt": created_at_lt, + "created_at_lte": created_at_lte, "cursor": cursor, "limit": limit, }, @@ -186,11 +418,11 @@ async def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CreditNote: """ - This endpoint is used to fetch a single - [`Credit Note`](../guides/invoicing/credit-notes) given an identifier. + This endpoint is used to fetch a single [`Credit Note`](/invoicing/credit-notes) + given an identifier. Args: extra_headers: Send extra headers @@ -204,7 +436,7 @@ async def fetch( if not credit_note_id: raise ValueError(f"Expected a non-empty value for `credit_note_id` but received {credit_note_id!r}") return await self._get( - f"/credit_notes/{credit_note_id}", + path_template("/credit_notes/{credit_note_id}", credit_note_id=credit_note_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -216,6 +448,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, ) @@ -228,6 +463,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, ) @@ -240,6 +478,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, ) @@ -252,6 +493,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/__init__.py b/src/orb/resources/customers/__init__.py index 4c6ee7aa..ffe4db5c 100644 --- a/src/orb/resources/customers/__init__.py +++ b/src/orb/resources/customers/__init__.py @@ -8,14 +8,6 @@ CostsWithStreamingResponse, AsyncCostsWithStreamingResponse, ) -from .usage import ( - Usage, - AsyncUsage, - UsageWithRawResponse, - AsyncUsageWithRawResponse, - UsageWithStreamingResponse, - AsyncUsageWithStreamingResponse, -) from .credits import ( Credits, AsyncCredits, @@ -48,12 +40,6 @@ "AsyncCostsWithRawResponse", "CostsWithStreamingResponse", "AsyncCostsWithStreamingResponse", - "Usage", - "AsyncUsage", - "UsageWithRawResponse", - "AsyncUsageWithRawResponse", - "UsageWithStreamingResponse", - "AsyncUsageWithStreamingResponse", "Credits", "AsyncCredits", "CreditsWithRawResponse", diff --git a/src/orb/resources/customers/balance_transactions.py b/src/orb/resources/customers/balance_transactions.py index 1616b066..a35733cb 100644 --- a/src/orb/resources/customers/balance_transactions.py +++ b/src/orb/resources/customers/balance_transactions.py @@ -9,36 +9,55 @@ import httpx from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import ( - maybe_transform, - async_maybe_transform, -) +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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 ...pagination import SyncPage, AsyncPage -from ..._base_client import ( - AsyncPaginator, - make_request_options, -) -from ...types.customers import ( - BalanceTransactionListResponse, - BalanceTransactionCreateResponse, - balance_transaction_list_params, - balance_transaction_create_params, -) +from ..._base_client import AsyncPaginator, make_request_options +from ...types.customers import balance_transaction_list_params, balance_transaction_create_params +from ...types.customers.balance_transaction_list_response import BalanceTransactionListResponse +from ...types.customers.balance_transaction_create_response import BalanceTransactionCreateResponse __all__ = ["BalanceTransactions", "AsyncBalanceTransactions"] class BalanceTransactions(SyncAPIResource): + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + @cached_property def with_raw_response(self) -> BalanceTransactionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -47,13 +66,13 @@ def create( *, amount: str, type: Literal["increment", "decrement"], - description: Optional[str] | NotGiven = NOT_GIVEN, + description: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> BalanceTransactionCreateResponse: """ @@ -76,7 +95,7 @@ def create( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return self._post( - f"/customers/{customer_id}/balance_transactions", + path_template("/customers/{customer_id}/balance_transactions", customer_id=customer_id), body=maybe_transform( { "amount": amount, @@ -99,18 +118,18 @@ def list( self, customer_id: str, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - operation_time_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - operation_time_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - operation_time_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - operation_time_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + operation_time_gt: Union[str, datetime, None] | Omit = omit, + operation_time_gte: Union[str, datetime, None] | Omit = omit, + operation_time_lt: Union[str, datetime, None] | Omit = omit, + operation_time_lte: Union[str, datetime, None] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[BalanceTransactionListResponse]: """ ## The customer balance @@ -135,13 +154,6 @@ def list( chronological order for a single customer, providing a complete audit trail of all adjustments and invoice applications. - ## Eligibility - - The customer balance can only be applied to invoices or adjusted manually if - invoices are not synced to a separate invoicing provider. If a payment gateway - such as Stripe is used, the balance will be applied to the invoice before - forwarding payment to the gateway. - Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned from the initial request. @@ -159,7 +171,7 @@ def list( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return self._get_api_list( - f"/customers/{customer_id}/balance_transactions", + path_template("/customers/{customer_id}/balance_transactions", customer_id=customer_id), page=SyncPage[BalanceTransactionListResponse], options=make_request_options( extra_headers=extra_headers, @@ -183,12 +195,40 @@ def list( class AsyncBalanceTransactions(AsyncAPIResource): + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + @cached_property def with_raw_response(self) -> AsyncBalanceTransactionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -197,13 +237,13 @@ async def create( *, amount: str, type: Literal["increment", "decrement"], - description: Optional[str] | NotGiven = NOT_GIVEN, + description: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> BalanceTransactionCreateResponse: """ @@ -226,7 +266,7 @@ async def create( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return await self._post( - f"/customers/{customer_id}/balance_transactions", + path_template("/customers/{customer_id}/balance_transactions", customer_id=customer_id), body=await async_maybe_transform( { "amount": amount, @@ -249,18 +289,18 @@ def list( self, customer_id: str, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - operation_time_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - operation_time_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - operation_time_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - operation_time_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + operation_time_gt: Union[str, datetime, None] | Omit = omit, + operation_time_gte: Union[str, datetime, None] | Omit = omit, + operation_time_lt: Union[str, datetime, None] | Omit = omit, + operation_time_lte: Union[str, datetime, None] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[BalanceTransactionListResponse, AsyncPage[BalanceTransactionListResponse]]: """ ## The customer balance @@ -285,13 +325,6 @@ def list( chronological order for a single customer, providing a complete audit trail of all adjustments and invoice applications. - ## Eligibility - - The customer balance can only be applied to invoices or adjusted manually if - invoices are not synced to a separate invoicing provider. If a payment gateway - such as Stripe is used, the balance will be applied to the invoice before - forwarding payment to the gateway. - Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned from the initial request. @@ -309,7 +342,7 @@ def list( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return self._get_api_list( - f"/customers/{customer_id}/balance_transactions", + path_template("/customers/{customer_id}/balance_transactions", customer_id=customer_id), page=AsyncPage[BalanceTransactionListResponse], options=make_request_options( extra_headers=extra_headers, diff --git a/src/orb/resources/customers/costs.py b/src/orb/resources/customers/costs.py index a735203e..0ccf347b 100644 --- a/src/orb/resources/customers/costs.py +++ b/src/orb/resources/customers/costs.py @@ -9,55 +9,76 @@ import httpx from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import ( - maybe_transform, - async_maybe_transform, -) +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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.customers import ( - CostListResponse, - CostListByExternalIDResponse, - cost_list_params, - cost_list_by_external_id_params, -) +from ..._base_client import make_request_options +from ...types.customers import cost_list_params, cost_list_by_external_id_params +from ...types.customers.cost_list_response import CostListResponse +from ...types.customers.cost_list_by_external_id_response import CostListByExternalIDResponse __all__ = ["Costs", "AsyncCosts"] class Costs(SyncAPIResource): + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + @cached_property def with_raw_response(self) -> CostsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( self, - customer_id: Optional[str], + customer_id: str, *, - timeframe_end: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - timeframe_start: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - view_mode: Optional[Literal["periodic", "cumulative"]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + timeframe_end: Union[str, datetime, None] | Omit = omit, + timeframe_start: Union[str, datetime, None] | Omit = omit, + view_mode: Optional[Literal["periodic", "cumulative"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CostListResponse: """ This endpoint is used to fetch a day-by-day snapshot of a customer's costs in Orb, calculated by applying pricing information to the underlying usage (see the - [subscription usage endpoint](fetch-subscription-usage.api.mdx) to fetch usage - per metric, in usage units rather than a currency). + [subscription usage endpoint](/api-reference/subscription/fetch-subscription-usage) + to fetch usage per metric, in usage units rather than a currency). This endpoint can be leveraged for internal tooling and to provide a more transparent billing experience for your end users: @@ -66,8 +87,8 @@ def list( the current billing period. 2. Provide customer visibility into how different services are contributing to the overall invoice with a per-day timeseries (as compared to the - [upcoming invoice](fetch-upcoming-invoice) resource, which represents a - snapshot for the current period). + [upcoming invoice](/api-reference/invoice/fetch-upcoming-invoice) resource, + which represents a snapshot for the current period). 3. Assess how minimums and discounts affect your customers by teasing apart costs directly as a result of usage, as opposed to minimums and discounts at the plan and price level. @@ -107,17 +128,17 @@ def list( A customer that uses a few API calls a day but has a minimum commitment might exhibit the following pattern for their subtotal and total in the first few days - of the month. Here, we assume that each API call is $2.50, the customer's plan - has a monthly minimum of $50 for this price, and that the subscription's billing - period bounds are aligned to the first of the month: + of the month. Here, we assume that each API call is \\$$2.50, the customer's plan + has a monthly minimum of \\$$50 for this price, and that the subscription's + billing period bounds are aligned to the first of the month: | timeframe_start | timeframe_end | Cumulative usage | Subtotal | Total (incl. commitment) | | --------------- | ------------- | ---------------- | -------- | ------------------------ | - | 2023-02-01 | 2023-02-02 | 9 | $22.50 | $50.00 | - | 2023-02-01 | 2023-02-03 | 19 | $47.50 | $50.00 | - | 2023-02-01 | 2023-02-04 | 20 | $50.00 | $50.00 | - | 2023-02-01 | 2023-02-05 | 28 | $70.00 | $70.00 | - | 2023-02-01 | 2023-02-06 | 36 | $90.00 | $90.00 | + | 2023-02-01 | 2023-02-02 | 9 | \\$$22.50 | \\$$50.00 | + | 2023-02-01 | 2023-02-03 | 19 | \\$$47.50 | \\$$50.00 | + | 2023-02-01 | 2023-02-04 | 20 | \\$$50.00 | \\$$50.00 | + | 2023-02-01 | 2023-02-05 | 28 | \\$$70.00 | \\$$70.00 | + | 2023-02-01 | 2023-02-06 | 36 | \\$$90.00 | \\$$90.00 | ### Periodic values @@ -132,11 +153,11 @@ def list( ## Timeframe bounds - If no timeframe bounds are specified, the response will default to the current - billing period for the customer's subscription. For subscriptions that have - ended, this will be the billing period when they were last active. If the - subscription starts or ends within the timeframe, the response will only include - windows where the subscription is active. + For an active subscription, both timeframes should be specified in the request. + If a subscription starts or ends within the timeframe, the response will only + include windows where the subscription is active. If a subscription has ended, + no timeframe bounds need to be specified and the response will default to the + billing period when the subscription was last active. As noted above, `timeframe_start` for a given cumulative datapoint is always the beginning of the billing period, and `timeframe_end` is incremented one day at a @@ -165,23 +186,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 @@ -190,6 +194,8 @@ def list( `grouping_value` and `secondary_grouping_value` available. Args: + currency: The currency or custom pricing unit to use. + timeframe_end: Costs returned are exclusive of `timeframe_end`. timeframe_start: Costs returned are inclusive of `timeframe_start`. @@ -210,7 +216,7 @@ def list( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return self._get( - f"/customers/{customer_id}/costs", + path_template("/customers/{customer_id}/costs", customer_id=customer_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -218,6 +224,7 @@ def list( timeout=timeout, query=maybe_transform( { + "currency": currency, "timeframe_end": timeframe_end, "timeframe_start": timeframe_start, "view_mode": view_mode, @@ -230,23 +237,24 @@ def list( def list_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, - timeframe_end: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - timeframe_start: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - view_mode: Optional[Literal["periodic", "cumulative"]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + timeframe_end: Union[str, datetime, None] | Omit = omit, + timeframe_start: Union[str, datetime, None] | Omit = omit, + view_mode: Optional[Literal["periodic", "cumulative"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CostListByExternalIDResponse: """ This endpoint is used to fetch a day-by-day snapshot of a customer's costs in Orb, calculated by applying pricing information to the underlying usage (see the - [subscription usage endpoint](fetch-subscription-usage.api.mdx) to fetch usage - per metric, in usage units rather than a currency). + [subscription usage endpoint](/api-reference/subscription/fetch-subscription-usage) + to fetch usage per metric, in usage units rather than a currency). This endpoint can be leveraged for internal tooling and to provide a more transparent billing experience for your end users: @@ -255,8 +263,8 @@ def list_by_external_id( the current billing period. 2. Provide customer visibility into how different services are contributing to the overall invoice with a per-day timeseries (as compared to the - [upcoming invoice](fetch-upcoming-invoice) resource, which represents a - snapshot for the current period). + [upcoming invoice](/api-reference/invoice/fetch-upcoming-invoice) resource, + which represents a snapshot for the current period). 3. Assess how minimums and discounts affect your customers by teasing apart costs directly as a result of usage, as opposed to minimums and discounts at the plan and price level. @@ -296,17 +304,17 @@ def list_by_external_id( A customer that uses a few API calls a day but has a minimum commitment might exhibit the following pattern for their subtotal and total in the first few days - of the month. Here, we assume that each API call is $2.50, the customer's plan - has a monthly minimum of $50 for this price, and that the subscription's billing - period bounds are aligned to the first of the month: + of the month. Here, we assume that each API call is \\$$2.50, the customer's plan + has a monthly minimum of \\$$50 for this price, and that the subscription's + billing period bounds are aligned to the first of the month: | timeframe_start | timeframe_end | Cumulative usage | Subtotal | Total (incl. commitment) | | --------------- | ------------- | ---------------- | -------- | ------------------------ | - | 2023-02-01 | 2023-02-02 | 9 | $22.50 | $50.00 | - | 2023-02-01 | 2023-02-03 | 19 | $47.50 | $50.00 | - | 2023-02-01 | 2023-02-04 | 20 | $50.00 | $50.00 | - | 2023-02-01 | 2023-02-05 | 28 | $70.00 | $70.00 | - | 2023-02-01 | 2023-02-06 | 36 | $90.00 | $90.00 | + | 2023-02-01 | 2023-02-02 | 9 | \\$$22.50 | \\$$50.00 | + | 2023-02-01 | 2023-02-03 | 19 | \\$$47.50 | \\$$50.00 | + | 2023-02-01 | 2023-02-04 | 20 | \\$$50.00 | \\$$50.00 | + | 2023-02-01 | 2023-02-05 | 28 | \\$$70.00 | \\$$70.00 | + | 2023-02-01 | 2023-02-06 | 36 | \\$$90.00 | \\$$90.00 | ### Periodic values @@ -321,11 +329,11 @@ def list_by_external_id( ## Timeframe bounds - If no timeframe bounds are specified, the response will default to the current - billing period for the customer's subscription. For subscriptions that have - ended, this will be the billing period when they were last active. If the - subscription starts or ends within the timeframe, the response will only include - windows where the subscription is active. + For an active subscription, both timeframes should be specified in the request. + If a subscription starts or ends within the timeframe, the response will only + include windows where the subscription is active. If a subscription has ended, + no timeframe bounds need to be specified and the response will default to the + billing period when the subscription was last active. As noted above, `timeframe_start` for a given cumulative datapoint is always the beginning of the billing period, and `timeframe_end` is incremented one day at a @@ -354,23 +362,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 @@ -379,6 +370,8 @@ def list_by_external_id( `grouping_value` and `secondary_grouping_value` available. Args: + currency: The currency or custom pricing unit to use. + timeframe_end: Costs returned are exclusive of `timeframe_end`. timeframe_start: Costs returned are inclusive of `timeframe_start`. @@ -401,7 +394,10 @@ def list_by_external_id( f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" ) return self._get( - f"/customers/external_customer_id/{external_customer_id}/costs", + path_template( + "/customers/external_customer_id/{external_customer_id}/costs", + external_customer_id=external_customer_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -409,6 +405,7 @@ def list_by_external_id( timeout=timeout, query=maybe_transform( { + "currency": currency, "timeframe_end": timeframe_end, "timeframe_start": timeframe_start, "view_mode": view_mode, @@ -421,33 +418,62 @@ def list_by_external_id( class AsyncCosts(AsyncAPIResource): + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + @cached_property def with_raw_response(self) -> AsyncCostsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( self, - customer_id: Optional[str], + customer_id: str, *, - timeframe_end: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - timeframe_start: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - view_mode: Optional[Literal["periodic", "cumulative"]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + timeframe_end: Union[str, datetime, None] | Omit = omit, + timeframe_start: Union[str, datetime, None] | Omit = omit, + view_mode: Optional[Literal["periodic", "cumulative"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CostListResponse: """ This endpoint is used to fetch a day-by-day snapshot of a customer's costs in Orb, calculated by applying pricing information to the underlying usage (see the - [subscription usage endpoint](fetch-subscription-usage.api.mdx) to fetch usage - per metric, in usage units rather than a currency). + [subscription usage endpoint](/api-reference/subscription/fetch-subscription-usage) + to fetch usage per metric, in usage units rather than a currency). This endpoint can be leveraged for internal tooling and to provide a more transparent billing experience for your end users: @@ -456,8 +482,8 @@ async def list( the current billing period. 2. Provide customer visibility into how different services are contributing to the overall invoice with a per-day timeseries (as compared to the - [upcoming invoice](fetch-upcoming-invoice) resource, which represents a - snapshot for the current period). + [upcoming invoice](/api-reference/invoice/fetch-upcoming-invoice) resource, + which represents a snapshot for the current period). 3. Assess how minimums and discounts affect your customers by teasing apart costs directly as a result of usage, as opposed to minimums and discounts at the plan and price level. @@ -497,17 +523,17 @@ async def list( A customer that uses a few API calls a day but has a minimum commitment might exhibit the following pattern for their subtotal and total in the first few days - of the month. Here, we assume that each API call is $2.50, the customer's plan - has a monthly minimum of $50 for this price, and that the subscription's billing - period bounds are aligned to the first of the month: + of the month. Here, we assume that each API call is \\$$2.50, the customer's plan + has a monthly minimum of \\$$50 for this price, and that the subscription's + billing period bounds are aligned to the first of the month: | timeframe_start | timeframe_end | Cumulative usage | Subtotal | Total (incl. commitment) | | --------------- | ------------- | ---------------- | -------- | ------------------------ | - | 2023-02-01 | 2023-02-02 | 9 | $22.50 | $50.00 | - | 2023-02-01 | 2023-02-03 | 19 | $47.50 | $50.00 | - | 2023-02-01 | 2023-02-04 | 20 | $50.00 | $50.00 | - | 2023-02-01 | 2023-02-05 | 28 | $70.00 | $70.00 | - | 2023-02-01 | 2023-02-06 | 36 | $90.00 | $90.00 | + | 2023-02-01 | 2023-02-02 | 9 | \\$$22.50 | \\$$50.00 | + | 2023-02-01 | 2023-02-03 | 19 | \\$$47.50 | \\$$50.00 | + | 2023-02-01 | 2023-02-04 | 20 | \\$$50.00 | \\$$50.00 | + | 2023-02-01 | 2023-02-05 | 28 | \\$$70.00 | \\$$70.00 | + | 2023-02-01 | 2023-02-06 | 36 | \\$$90.00 | \\$$90.00 | ### Periodic values @@ -522,11 +548,11 @@ async def list( ## Timeframe bounds - If no timeframe bounds are specified, the response will default to the current - billing period for the customer's subscription. For subscriptions that have - ended, this will be the billing period when they were last active. If the - subscription starts or ends within the timeframe, the response will only include - windows where the subscription is active. + For an active subscription, both timeframes should be specified in the request. + If a subscription starts or ends within the timeframe, the response will only + include windows where the subscription is active. If a subscription has ended, + no timeframe bounds need to be specified and the response will default to the + billing period when the subscription was last active. As noted above, `timeframe_start` for a given cumulative datapoint is always the beginning of the billing period, and `timeframe_end` is incremented one day at a @@ -555,23 +581,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 @@ -580,6 +589,8 @@ async def list( `grouping_value` and `secondary_grouping_value` available. Args: + currency: The currency or custom pricing unit to use. + timeframe_end: Costs returned are exclusive of `timeframe_end`. timeframe_start: Costs returned are inclusive of `timeframe_start`. @@ -600,7 +611,7 @@ async def list( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return await self._get( - f"/customers/{customer_id}/costs", + path_template("/customers/{customer_id}/costs", customer_id=customer_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -608,6 +619,7 @@ async def list( timeout=timeout, query=await async_maybe_transform( { + "currency": currency, "timeframe_end": timeframe_end, "timeframe_start": timeframe_start, "view_mode": view_mode, @@ -620,23 +632,24 @@ async def list( async def list_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, - timeframe_end: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - timeframe_start: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - view_mode: Optional[Literal["periodic", "cumulative"]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + timeframe_end: Union[str, datetime, None] | Omit = omit, + timeframe_start: Union[str, datetime, None] | Omit = omit, + view_mode: Optional[Literal["periodic", "cumulative"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CostListByExternalIDResponse: """ This endpoint is used to fetch a day-by-day snapshot of a customer's costs in Orb, calculated by applying pricing information to the underlying usage (see the - [subscription usage endpoint](fetch-subscription-usage.api.mdx) to fetch usage - per metric, in usage units rather than a currency). + [subscription usage endpoint](/api-reference/subscription/fetch-subscription-usage) + to fetch usage per metric, in usage units rather than a currency). This endpoint can be leveraged for internal tooling and to provide a more transparent billing experience for your end users: @@ -645,8 +658,8 @@ async def list_by_external_id( the current billing period. 2. Provide customer visibility into how different services are contributing to the overall invoice with a per-day timeseries (as compared to the - [upcoming invoice](fetch-upcoming-invoice) resource, which represents a - snapshot for the current period). + [upcoming invoice](/api-reference/invoice/fetch-upcoming-invoice) resource, + which represents a snapshot for the current period). 3. Assess how minimums and discounts affect your customers by teasing apart costs directly as a result of usage, as opposed to minimums and discounts at the plan and price level. @@ -686,17 +699,17 @@ async def list_by_external_id( A customer that uses a few API calls a day but has a minimum commitment might exhibit the following pattern for their subtotal and total in the first few days - of the month. Here, we assume that each API call is $2.50, the customer's plan - has a monthly minimum of $50 for this price, and that the subscription's billing - period bounds are aligned to the first of the month: + of the month. Here, we assume that each API call is \\$$2.50, the customer's plan + has a monthly minimum of \\$$50 for this price, and that the subscription's + billing period bounds are aligned to the first of the month: | timeframe_start | timeframe_end | Cumulative usage | Subtotal | Total (incl. commitment) | | --------------- | ------------- | ---------------- | -------- | ------------------------ | - | 2023-02-01 | 2023-02-02 | 9 | $22.50 | $50.00 | - | 2023-02-01 | 2023-02-03 | 19 | $47.50 | $50.00 | - | 2023-02-01 | 2023-02-04 | 20 | $50.00 | $50.00 | - | 2023-02-01 | 2023-02-05 | 28 | $70.00 | $70.00 | - | 2023-02-01 | 2023-02-06 | 36 | $90.00 | $90.00 | + | 2023-02-01 | 2023-02-02 | 9 | \\$$22.50 | \\$$50.00 | + | 2023-02-01 | 2023-02-03 | 19 | \\$$47.50 | \\$$50.00 | + | 2023-02-01 | 2023-02-04 | 20 | \\$$50.00 | \\$$50.00 | + | 2023-02-01 | 2023-02-05 | 28 | \\$$70.00 | \\$$70.00 | + | 2023-02-01 | 2023-02-06 | 36 | \\$$90.00 | \\$$90.00 | ### Periodic values @@ -711,11 +724,11 @@ async def list_by_external_id( ## Timeframe bounds - If no timeframe bounds are specified, the response will default to the current - billing period for the customer's subscription. For subscriptions that have - ended, this will be the billing period when they were last active. If the - subscription starts or ends within the timeframe, the response will only include - windows where the subscription is active. + For an active subscription, both timeframes should be specified in the request. + If a subscription starts or ends within the timeframe, the response will only + include windows where the subscription is active. If a subscription has ended, + no timeframe bounds need to be specified and the response will default to the + billing period when the subscription was last active. As noted above, `timeframe_start` for a given cumulative datapoint is always the beginning of the billing period, and `timeframe_end` is incremented one day at a @@ -744,23 +757,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 @@ -769,6 +765,8 @@ async def list_by_external_id( `grouping_value` and `secondary_grouping_value` available. Args: + currency: The currency or custom pricing unit to use. + timeframe_end: Costs returned are exclusive of `timeframe_end`. timeframe_start: Costs returned are inclusive of `timeframe_start`. @@ -791,7 +789,10 @@ async def list_by_external_id( f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" ) return await self._get( - f"/customers/external_customer_id/{external_customer_id}/costs", + path_template( + "/customers/external_customer_id/{external_customer_id}/costs", + external_customer_id=external_customer_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -799,6 +800,7 @@ async def list_by_external_id( timeout=timeout, query=await async_maybe_transform( { + "currency": currency, "timeframe_end": timeframe_end, "timeframe_start": timeframe_start, "view_mode": view_mode, diff --git a/src/orb/resources/customers/credits/credits.py b/src/orb/resources/customers/credits/credits.py index 3d25402c..21eee7d2 100644 --- a/src/orb/resources/customers/credits/credits.py +++ b/src/orb/resources/customers/credits/credits.py @@ -2,7 +2,8 @@ from __future__ import annotations -from typing import Optional +from typing import Union, Optional +from datetime import datetime import httpx @@ -23,66 +24,100 @@ TopUpsWithStreamingResponse, AsyncTopUpsWithStreamingResponse, ) -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import maybe_transform +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import path_template, 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 ....pagination import SyncPage, AsyncPage -from ...._base_client import ( - AsyncPaginator, - make_request_options, -) -from ....types.customers import ( - CreditListResponse, - CreditListByExternalIDResponse, - credit_list_params, - credit_list_by_external_id_params, -) +from ...._base_client import AsyncPaginator, make_request_options +from ....types.customers import credit_list_params, credit_list_by_external_id_params +from ....types.customers.credit_list_response import CreditListResponse +from ....types.customers.credit_list_by_external_id_response import CreditListByExternalIDResponse __all__ = ["Credits", "AsyncCredits"] class Credits(SyncAPIResource): + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ + @cached_property def ledger(self) -> Ledger: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return Ledger(self._client) @cached_property def top_ups(self) -> TopUps: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return TopUps(self._client) @cached_property def with_raw_response(self) -> CreditsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( self, - customer_id: Optional[str], + customer_id: str, *, - currency: Optional[str] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + cursor: Optional[str] | Omit = omit, + effective_date_gt: Union[str, datetime, None] | Omit = omit, + effective_date_gte: Union[str, datetime, None] | Omit = omit, + effective_date_lt: Union[str, datetime, None] | Omit = omit, + effective_date_lte: Union[str, datetime, None] | Omit = omit, + include_all_blocks: bool | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[CreditListResponse]: """ Returns a paginated list of unexpired, non-zero credit blocks for a customer. + If `include_all_blocks` is set to `true`, all credit blocks (including expired + and depleted blocks) will be included in the response. + + Note that `currency` defaults to credits if not specified. To use a real world + currency, set `currency` to an ISO 4217 string. + + Results can be filtered by the block's `effective_date` using the + `effective_date[gte]`, `effective_date[gt]`, `effective_date[lt]`, and + `effective_date[lte]` query parameters. This filters on when the credit block + becomes effective, which may differ from creation time for backdated credits. + Args: currency: The ledger currency or custom pricing unit to use. cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned from the initial request. + include_all_blocks: If set to True, all expired and depleted blocks, as well as active block will be + returned. + limit: The number of items to fetch. Defaults to 20. extra_headers: Send extra headers @@ -96,7 +131,7 @@ def list( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return self._get_api_list( - f"/customers/{customer_id}/credits", + path_template("/customers/{customer_id}/credits", customer_id=customer_id), page=SyncPage[CreditListResponse], options=make_request_options( extra_headers=extra_headers, @@ -107,6 +142,11 @@ def list( { "currency": currency, "cursor": cursor, + "effective_date_gt": effective_date_gt, + "effective_date_gte": effective_date_gte, + "effective_date_lt": effective_date_lt, + "effective_date_lte": effective_date_lte, + "include_all_blocks": include_all_blocks, "limit": limit, }, credit_list_params.CreditListParams, @@ -117,27 +157,46 @@ def list( def list_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, - currency: Optional[str] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + cursor: Optional[str] | Omit = omit, + effective_date_gt: Union[str, datetime, None] | Omit = omit, + effective_date_gte: Union[str, datetime, None] | Omit = omit, + effective_date_lt: Union[str, datetime, None] | Omit = omit, + effective_date_lte: Union[str, datetime, None] | Omit = omit, + include_all_blocks: bool | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[CreditListByExternalIDResponse]: """ Returns a paginated list of unexpired, non-zero credit blocks for a customer. + If `include_all_blocks` is set to `true`, all credit blocks (including expired + and depleted blocks) will be included in the response. + + Note that `currency` defaults to credits if not specified. To use a real world + currency, set `currency` to an ISO 4217 string. + + Results can be filtered by the block's `effective_date` using the + `effective_date[gte]`, `effective_date[gt]`, `effective_date[lt]`, and + `effective_date[lte]` query parameters. This filters on when the credit block + becomes effective, which may differ from creation time for backdated credits. + Args: currency: The ledger currency or custom pricing unit to use. cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned from the initial request. + include_all_blocks: If set to True, all expired and depleted blocks, as well as active block will be + returned. + limit: The number of items to fetch. Defaults to 20. extra_headers: Send extra headers @@ -153,7 +212,10 @@ def list_by_external_id( f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" ) return self._get_api_list( - f"/customers/external_customer_id/{external_customer_id}/credits", + path_template( + "/customers/external_customer_id/{external_customer_id}/credits", + external_customer_id=external_customer_id, + ), page=SyncPage[CreditListByExternalIDResponse], options=make_request_options( extra_headers=extra_headers, @@ -164,6 +226,11 @@ def list_by_external_id( { "currency": currency, "cursor": cursor, + "effective_date_gt": effective_date_gt, + "effective_date_gte": effective_date_gte, + "effective_date_lt": effective_date_lt, + "effective_date_lte": effective_date_lte, + "include_all_blocks": include_all_blocks, "limit": limit, }, credit_list_by_external_id_params.CreditListByExternalIDParams, @@ -174,45 +241,85 @@ def list_by_external_id( class AsyncCredits(AsyncAPIResource): + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ + @cached_property def ledger(self) -> AsyncLedger: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return AsyncLedger(self._client) @cached_property def top_ups(self) -> AsyncTopUps: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return AsyncTopUps(self._client) @cached_property def with_raw_response(self) -> AsyncCreditsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( self, - customer_id: Optional[str], + customer_id: str, *, - currency: Optional[str] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + cursor: Optional[str] | Omit = omit, + effective_date_gt: Union[str, datetime, None] | Omit = omit, + effective_date_gte: Union[str, datetime, None] | Omit = omit, + effective_date_lt: Union[str, datetime, None] | Omit = omit, + effective_date_lte: Union[str, datetime, None] | Omit = omit, + include_all_blocks: bool | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[CreditListResponse, AsyncPage[CreditListResponse]]: """ Returns a paginated list of unexpired, non-zero credit blocks for a customer. + If `include_all_blocks` is set to `true`, all credit blocks (including expired + and depleted blocks) will be included in the response. + + Note that `currency` defaults to credits if not specified. To use a real world + currency, set `currency` to an ISO 4217 string. + + Results can be filtered by the block's `effective_date` using the + `effective_date[gte]`, `effective_date[gt]`, `effective_date[lt]`, and + `effective_date[lte]` query parameters. This filters on when the credit block + becomes effective, which may differ from creation time for backdated credits. + Args: currency: The ledger currency or custom pricing unit to use. cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned from the initial request. + include_all_blocks: If set to True, all expired and depleted blocks, as well as active block will be + returned. + limit: The number of items to fetch. Defaults to 20. extra_headers: Send extra headers @@ -226,7 +333,7 @@ def list( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return self._get_api_list( - f"/customers/{customer_id}/credits", + path_template("/customers/{customer_id}/credits", customer_id=customer_id), page=AsyncPage[CreditListResponse], options=make_request_options( extra_headers=extra_headers, @@ -237,6 +344,11 @@ def list( { "currency": currency, "cursor": cursor, + "effective_date_gt": effective_date_gt, + "effective_date_gte": effective_date_gte, + "effective_date_lt": effective_date_lt, + "effective_date_lte": effective_date_lte, + "include_all_blocks": include_all_blocks, "limit": limit, }, credit_list_params.CreditListParams, @@ -247,27 +359,46 @@ def list( def list_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, - currency: Optional[str] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + cursor: Optional[str] | Omit = omit, + effective_date_gt: Union[str, datetime, None] | Omit = omit, + effective_date_gte: Union[str, datetime, None] | Omit = omit, + effective_date_lt: Union[str, datetime, None] | Omit = omit, + effective_date_lte: Union[str, datetime, None] | Omit = omit, + include_all_blocks: bool | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[CreditListByExternalIDResponse, AsyncPage[CreditListByExternalIDResponse]]: """ Returns a paginated list of unexpired, non-zero credit blocks for a customer. + If `include_all_blocks` is set to `true`, all credit blocks (including expired + and depleted blocks) will be included in the response. + + Note that `currency` defaults to credits if not specified. To use a real world + currency, set `currency` to an ISO 4217 string. + + Results can be filtered by the block's `effective_date` using the + `effective_date[gte]`, `effective_date[gt]`, `effective_date[lt]`, and + `effective_date[lte]` query parameters. This filters on when the credit block + becomes effective, which may differ from creation time for backdated credits. + Args: currency: The ledger currency or custom pricing unit to use. cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned from the initial request. + include_all_blocks: If set to True, all expired and depleted blocks, as well as active block will be + returned. + limit: The number of items to fetch. Defaults to 20. extra_headers: Send extra headers @@ -283,7 +414,10 @@ def list_by_external_id( f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" ) return self._get_api_list( - f"/customers/external_customer_id/{external_customer_id}/credits", + path_template( + "/customers/external_customer_id/{external_customer_id}/credits", + external_customer_id=external_customer_id, + ), page=AsyncPage[CreditListByExternalIDResponse], options=make_request_options( extra_headers=extra_headers, @@ -294,6 +428,11 @@ def list_by_external_id( { "currency": currency, "cursor": cursor, + "effective_date_gt": effective_date_gt, + "effective_date_gte": effective_date_gte, + "effective_date_lt": effective_date_lt, + "effective_date_lte": effective_date_lte, + "include_all_blocks": include_all_blocks, "limit": limit, }, credit_list_by_external_id_params.CreditListByExternalIDParams, @@ -316,10 +455,16 @@ def __init__(self, credits: Credits) -> None: @cached_property def ledger(self) -> LedgerWithRawResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return LedgerWithRawResponse(self._credits.ledger) @cached_property def top_ups(self) -> TopUpsWithRawResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return TopUpsWithRawResponse(self._credits.top_ups) @@ -336,10 +481,16 @@ def __init__(self, credits: AsyncCredits) -> None: @cached_property def ledger(self) -> AsyncLedgerWithRawResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return AsyncLedgerWithRawResponse(self._credits.ledger) @cached_property def top_ups(self) -> AsyncTopUpsWithRawResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return AsyncTopUpsWithRawResponse(self._credits.top_ups) @@ -356,10 +507,16 @@ def __init__(self, credits: Credits) -> None: @cached_property def ledger(self) -> LedgerWithStreamingResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return LedgerWithStreamingResponse(self._credits.ledger) @cached_property def top_ups(self) -> TopUpsWithStreamingResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return TopUpsWithStreamingResponse(self._credits.top_ups) @@ -376,8 +533,14 @@ def __init__(self, credits: AsyncCredits) -> None: @cached_property def ledger(self) -> AsyncLedgerWithStreamingResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return AsyncLedgerWithStreamingResponse(self._credits.ledger) @cached_property def top_ups(self) -> AsyncTopUpsWithStreamingResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return AsyncTopUpsWithStreamingResponse(self._credits.top_ups) diff --git a/src/orb/resources/customers/credits/ledger.py b/src/orb/resources/customers/credits/ledger.py index d7539c6d..aae9d30f 100644 --- a/src/orb/resources/customers/credits/ledger.py +++ b/src/orb/resources/customers/credits/ledger.py @@ -2,61 +2,71 @@ from __future__ import annotations -from typing import Any, Dict, Union, Optional, cast, overload +from typing import Any, Dict, Union, Iterable, Optional, cast from datetime import date, datetime -from typing_extensions import Literal +from typing_extensions import Literal, overload import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import ( - required_args, - maybe_transform, - async_maybe_transform, -) +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import path_template, required_args, 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 ....pagination import SyncPage, AsyncPage -from ...._base_client import ( - AsyncPaginator, - make_request_options, -) +from ...._base_client import AsyncPaginator, make_request_options from ....types.customers.credits import ( - LedgerListResponse, - LedgerCreateEntryResponse, - LedgerListByExternalIDResponse, - LedgerCreateEntryByExternalIDResponse, ledger_list_params, ledger_create_entry_params, ledger_list_by_external_id_params, ledger_create_entry_by_external_id_params, ) +from ....types.customers.credits.ledger_list_response import LedgerListResponse +from ....types.customers.credits.ledger_create_entry_response import LedgerCreateEntryResponse +from ....types.customers.credits.ledger_list_by_external_id_response import LedgerListByExternalIDResponse +from ....types.customers.credits.ledger_create_entry_by_external_id_response import ( + LedgerCreateEntryByExternalIDResponse, +) __all__ = ["Ledger", "AsyncLedger"] class Ledger(SyncAPIResource): + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ + @cached_property def with_raw_response(self) -> LedgerWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( self, - customer_id: Optional[str], + customer_id: str, *, - created_at_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - currency: Optional[str] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - entry_status: Optional[Literal["committed", "pending"]] | NotGiven = NOT_GIVEN, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + currency: Optional[str] | Omit = omit, + cursor: Optional[str] | Omit = omit, + entry_status: Optional[Literal["committed", "pending"]] | Omit = omit, entry_type: Optional[ Literal[ "increment", @@ -68,24 +78,24 @@ def list( "amendment", ] ] - | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - minimum_amount: Optional[str] | NotGiven = NOT_GIVEN, + | Omit = omit, + limit: int | Omit = omit, + minimum_amount: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[LedgerListResponse]: """ The credits ledger provides _auditing_ functionality over Orb's credits system with a list of actions that have taken place to modify a customer's credit - balance. This [paginated endpoint](../reference/pagination) lists these entries, - starting from the most recent ledger entry. + balance. This [paginated endpoint](/api-reference/pagination) lists these + entries, starting from the most recent ledger entry. More details on using Orb's real-time credit feature are - [here](../guides/product-catalog/prepurchase.md). + [here](/product-catalog/prepurchase). There are four major types of modifications to credit balance, detailed below. @@ -104,11 +114,9 @@ def list( As usage for a customer is reported into Orb, credits may be deducted according to the customer's plan configuration. An automated deduction of this type will - result in a ledger entry, also with a starting and ending balance. In order to - provide better tracing capabilities for automatic deductions, Orb always - associates each automatic deduction with the `event_id` at the time of - ingestion, used to pinpoint _why_ credit deduction took place and to ensure that - credits are never deducted without an associated usage event. + result in a ledger entry, also with a starting and ending balance. Each day's + usage for a particular price, invoice, and block will be grouped into a single + entry. By default, Orb uses an algorithm that automatically deducts from the _soonest expiring credit block_ first in order to ensure that all credits are utilized @@ -117,8 +125,8 @@ def list( deductions take place from a non-expiring credit block. If there are multiple blocks with the same expiration date, Orb will deduct from - the block with the _lower cost basis_ first (e.g. trial credits with a $0 cost - basis before paid credits with a $5.00 cost basis). + the block with the _lower cost basis_ first (e.g. trial credits with a \\$$0 cost + basis before paid credits with a \\$$5.00 cost basis). It's also possible for a single usage event's deduction to _span_ credit blocks. In this case, Orb will deduct from the next block, ending at the credit block @@ -136,7 +144,7 @@ def list( Note that for this entry type, `starting_balance` will equal `ending_balance`, and the `amount` represents the balance transferred. The credit block linked to the ledger entry is the source credit block from which there was an expiration - change + change. ## Credits expiry @@ -180,7 +188,7 @@ def list( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return self._get_api_list( - f"/customers/{customer_id}/credits/ledger", + path_template("/customers/{customer_id}/credits/ledger", customer_id=customer_id), page=SyncPage[LedgerListResponse], options=make_request_options( extra_headers=extra_headers, @@ -209,24 +217,26 @@ def list( @overload def create_entry( self, - customer_id: Optional[str], + customer_id: str, *, amount: float, entry_type: Literal["increment"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - effective_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - expiry_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + effective_date: Union[str, datetime, None] | Omit = omit, + expiry_date: Union[str, datetime, None] | Omit = omit, + filters: Optional[Iterable[ledger_create_entry_params.AddIncrementCreditLedgerEntryRequestParamsFilter]] + | Omit = omit, invoice_settings: Optional[ledger_create_entry_params.AddIncrementCreditLedgerEntryRequestParamsInvoiceSettings] - | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - per_unit_cost_basis: Optional[str] | NotGiven = NOT_GIVEN, + | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + per_unit_cost_basis: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryResponse: """ @@ -240,10 +250,11 @@ def create_entry( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -269,8 +280,9 @@ def create_entry( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -279,16 +291,29 @@ def create_entry( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -356,6 +381,9 @@ def create_entry( expiry_date: An ISO 8601 format date that denotes when this credit balance should expire. + filters: Optional filter to specify which items this credit block applies to. If not + specified, the block will apply to all items for the pricing unit. + invoice_settings: Passing `invoice_settings` automatically generates an invoice for the newly added credits. If `invoice_settings` is passed, you must specify per_unit_cost_basis, as the calculation of the invoice total is done on that @@ -365,8 +393,8 @@ def create_entry( by setting the value to `null`, and the entire metadata mapping can be cleared by setting `metadata` to `null`. - per_unit_cost_basis: Can only be specified when entry_type=increment. How much, in USD, a customer - paid for a single credit in this block + per_unit_cost_basis: Can only be specified when entry_type=increment. How much, in the customer's + currency, a customer paid for a single credit in this block extra_headers: Send extra headers @@ -383,19 +411,19 @@ def create_entry( @overload def create_entry( self, - customer_id: Optional[str], + customer_id: str, *, amount: float, entry_type: Literal["decrement"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryResponse: """ @@ -409,10 +437,11 @@ def create_entry( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -438,8 +467,9 @@ def create_entry( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -448,16 +478,29 @@ def create_entry( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -539,22 +582,22 @@ def create_entry( @overload def create_entry( self, - customer_id: Optional[str], + customer_id: str, *, entry_type: Literal["expiration_change"], - expiry_date: Union[str, datetime, None], target_expiry_date: Union[str, date], - amount: Optional[float] | NotGiven = NOT_GIVEN, - block_id: Optional[str] | NotGiven = NOT_GIVEN, - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + amount: Optional[float] | Omit = omit, + block_id: Optional[str] | Omit = omit, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + expiry_date: Union[str, datetime, None] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryResponse: """ @@ -568,10 +611,11 @@ def create_entry( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -597,8 +641,9 @@ def create_entry( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -607,16 +652,29 @@ def create_entry( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -669,11 +727,9 @@ def create_entry( return to the customer, up to the block's initial balance. Args: - expiry_date: An ISO 8601 format date that identifies the origination credit block to expire - - target_expiry_date: A future date (specified in YYYY-MM-DD format) used for expiration change, - denoting when credits transferred (as part of a partial block expiration) should - expire. + target_expiry_date: A date (specified in YYYY-MM-DD format) used for expiration change, denoting + when credits transferred (as part of a partial block expiration) should expire. + This date must be on or after the effective date of the credit block. amount: The number of credits to effect. Note that this is required for increment, decrement, void, or undo operations. @@ -688,6 +744,8 @@ def create_entry( For example, this can be used to note an increment refers to trial credits, or for noting corrections as a result of an incident, etc. + expiry_date: An ISO 8601 format date that identifies the origination credit block to expire + 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`. @@ -707,21 +765,21 @@ def create_entry( @overload def create_entry( self, - customer_id: Optional[str], + customer_id: str, *, amount: float, block_id: str, entry_type: Literal["void"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - void_reason: Optional[Literal["refund"]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + void_reason: Optional[Literal["refund"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryResponse: """ @@ -735,10 +793,11 @@ def create_entry( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -764,8 +823,9 @@ def create_entry( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -774,16 +834,29 @@ def create_entry( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -869,20 +942,20 @@ def create_entry( @overload def create_entry( self, - customer_id: Optional[str], + customer_id: str, *, amount: float, block_id: str, entry_type: Literal["amendment"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryResponse: """ @@ -896,10 +969,11 @@ def create_entry( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -925,8 +999,9 @@ def create_entry( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -935,16 +1010,29 @@ def create_entry( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -1025,40 +1113,36 @@ def create_entry( """ ... - @required_args( - ["amount", "entry_type"], - ["amount", "entry_type"], - ["entry_type", "expiry_date", "target_expiry_date"], - ["amount", "block_id", "entry_type"], - ["amount", "block_id", "entry_type"], - ) + @required_args(["amount", "entry_type"], ["entry_type", "target_expiry_date"], ["amount", "block_id", "entry_type"]) def create_entry( self, - customer_id: Optional[str], + customer_id: str, *, - amount: float | None | NotGiven = NOT_GIVEN, + amount: float | Optional[float] | Omit = omit, entry_type: Literal["increment"] | Literal["decrement"] | Literal["expiration_change"] | Literal["void"] | Literal["amendment"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - effective_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - expiry_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + effective_date: Union[str, datetime, None] | Omit = omit, + expiry_date: Union[str, datetime, None] | Omit = omit, + filters: Optional[Iterable[ledger_create_entry_params.AddIncrementCreditLedgerEntryRequestParamsFilter]] + | Omit = omit, invoice_settings: Optional[ledger_create_entry_params.AddIncrementCreditLedgerEntryRequestParamsInvoiceSettings] - | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - per_unit_cost_basis: Optional[str] | NotGiven = NOT_GIVEN, - target_expiry_date: Union[str, date] | NotGiven = NOT_GIVEN, - block_id: Optional[str] | NotGiven = NOT_GIVEN, - void_reason: Optional[Literal["refund"]] | NotGiven = NOT_GIVEN, + | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + per_unit_cost_basis: Optional[str] | Omit = omit, + target_expiry_date: Union[str, date] | Omit = omit, + block_id: Optional[str] | str | Omit = omit, + void_reason: Optional[Literal["refund"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryResponse: if not customer_id: @@ -1066,7 +1150,7 @@ def create_entry( return cast( LedgerCreateEntryResponse, self._post( - f"/customers/{customer_id}/credits/ledger_entry", + path_template("/customers/{customer_id}/credits/ledger_entry", customer_id=customer_id), body=maybe_transform( { "amount": amount, @@ -1075,6 +1159,7 @@ def create_entry( "description": description, "effective_date": effective_date, "expiry_date": expiry_date, + "filters": filters, "invoice_settings": invoice_settings, "metadata": metadata, "per_unit_cost_basis": per_unit_cost_basis, @@ -1100,26 +1185,30 @@ def create_entry( @overload def create_entry_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, amount: float, entry_type: Literal["increment"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - effective_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - expiry_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + effective_date: Union[str, datetime, None] | Omit = omit, + expiry_date: Union[str, datetime, None] | Omit = omit, + filters: Optional[ + Iterable[ledger_create_entry_by_external_id_params.AddIncrementCreditLedgerEntryRequestParamsFilter] + ] + | Omit = omit, invoice_settings: Optional[ ledger_create_entry_by_external_id_params.AddIncrementCreditLedgerEntryRequestParamsInvoiceSettings ] - | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - per_unit_cost_basis: Optional[str] | NotGiven = NOT_GIVEN, + | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + per_unit_cost_basis: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryByExternalIDResponse: """ @@ -1133,10 +1222,11 @@ def create_entry_by_external_id( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -1162,8 +1252,9 @@ def create_entry_by_external_id( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -1172,16 +1263,29 @@ def create_entry_by_external_id( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -1249,6 +1353,9 @@ def create_entry_by_external_id( expiry_date: An ISO 8601 format date that denotes when this credit balance should expire. + filters: Optional filter to specify which items this credit block applies to. If not + specified, the block will apply to all items for the pricing unit. + invoice_settings: Passing `invoice_settings` automatically generates an invoice for the newly added credits. If `invoice_settings` is passed, you must specify per_unit_cost_basis, as the calculation of the invoice total is done on that @@ -1258,8 +1365,8 @@ def create_entry_by_external_id( by setting the value to `null`, and the entire metadata mapping can be cleared by setting `metadata` to `null`. - per_unit_cost_basis: Can only be specified when entry_type=increment. How much, in USD, a customer - paid for a single credit in this block + per_unit_cost_basis: Can only be specified when entry_type=increment. How much, in the customer's + currency, a customer paid for a single credit in this block extra_headers: Send extra headers @@ -1276,19 +1383,19 @@ def create_entry_by_external_id( @overload def create_entry_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, amount: float, entry_type: Literal["decrement"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryByExternalIDResponse: """ @@ -1302,10 +1409,11 @@ def create_entry_by_external_id( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -1331,8 +1439,9 @@ def create_entry_by_external_id( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -1341,16 +1450,29 @@ def create_entry_by_external_id( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -1432,22 +1554,22 @@ def create_entry_by_external_id( @overload def create_entry_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, entry_type: Literal["expiration_change"], - expiry_date: Union[str, datetime, None], target_expiry_date: Union[str, date], - amount: Optional[float] | NotGiven = NOT_GIVEN, - block_id: Optional[str] | NotGiven = NOT_GIVEN, - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + amount: Optional[float] | Omit = omit, + block_id: Optional[str] | Omit = omit, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + expiry_date: Union[str, datetime, None] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryByExternalIDResponse: """ @@ -1461,10 +1583,11 @@ def create_entry_by_external_id( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -1490,8 +1613,9 @@ def create_entry_by_external_id( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -1500,16 +1624,29 @@ def create_entry_by_external_id( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -1562,11 +1699,9 @@ def create_entry_by_external_id( return to the customer, up to the block's initial balance. Args: - expiry_date: An ISO 8601 format date that identifies the origination credit block to expire - - target_expiry_date: A future date (specified in YYYY-MM-DD format) used for expiration change, - denoting when credits transferred (as part of a partial block expiration) should - expire. + target_expiry_date: A date (specified in YYYY-MM-DD format) used for expiration change, denoting + when credits transferred (as part of a partial block expiration) should expire. + This date must be on or after the effective date of the credit block. amount: The number of credits to effect. Note that this is required for increment, decrement, void, or undo operations. @@ -1581,6 +1716,8 @@ def create_entry_by_external_id( For example, this can be used to note an increment refers to trial credits, or for noting corrections as a result of an incident, etc. + expiry_date: An ISO 8601 format date that identifies the origination credit block to expire + 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`. @@ -1600,21 +1737,21 @@ def create_entry_by_external_id( @overload def create_entry_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, amount: float, block_id: str, entry_type: Literal["void"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - void_reason: Optional[Literal["refund"]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + void_reason: Optional[Literal["refund"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryByExternalIDResponse: """ @@ -1628,10 +1765,11 @@ def create_entry_by_external_id( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -1657,8 +1795,9 @@ def create_entry_by_external_id( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -1667,16 +1806,29 @@ def create_entry_by_external_id( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -1762,20 +1914,20 @@ def create_entry_by_external_id( @overload def create_entry_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, amount: float, block_id: str, entry_type: Literal["amendment"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryByExternalIDResponse: """ @@ -1789,10 +1941,11 @@ def create_entry_by_external_id( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -1818,8 +1971,9 @@ def create_entry_by_external_id( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -1828,16 +1982,29 @@ def create_entry_by_external_id( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -1918,42 +2085,40 @@ def create_entry_by_external_id( """ ... - @required_args( - ["amount", "entry_type"], - ["amount", "entry_type"], - ["entry_type", "expiry_date", "target_expiry_date"], - ["amount", "block_id", "entry_type"], - ["amount", "block_id", "entry_type"], - ) + @required_args(["amount", "entry_type"], ["entry_type", "target_expiry_date"], ["amount", "block_id", "entry_type"]) def create_entry_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, - amount: float | None | NotGiven = NOT_GIVEN, + amount: float | Optional[float] | Omit = omit, entry_type: Literal["increment"] | Literal["decrement"] | Literal["expiration_change"] | Literal["void"] | Literal["amendment"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - effective_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - expiry_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + effective_date: Union[str, datetime, None] | Omit = omit, + expiry_date: Union[str, datetime, None] | Omit = omit, + filters: Optional[ + Iterable[ledger_create_entry_by_external_id_params.AddIncrementCreditLedgerEntryRequestParamsFilter] + ] + | Omit = omit, invoice_settings: Optional[ ledger_create_entry_by_external_id_params.AddIncrementCreditLedgerEntryRequestParamsInvoiceSettings ] - | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - per_unit_cost_basis: Optional[str] | NotGiven = NOT_GIVEN, - target_expiry_date: Union[str, date] | NotGiven = NOT_GIVEN, - block_id: Optional[str] | NotGiven = NOT_GIVEN, - void_reason: Optional[Literal["refund"]] | NotGiven = NOT_GIVEN, + | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + per_unit_cost_basis: Optional[str] | Omit = omit, + target_expiry_date: Union[str, date] | Omit = omit, + block_id: Optional[str] | str | Omit = omit, + void_reason: Optional[Literal["refund"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryByExternalIDResponse: if not external_customer_id: @@ -1963,7 +2128,10 @@ def create_entry_by_external_id( return cast( LedgerCreateEntryByExternalIDResponse, self._post( - f"/customers/external_customer_id/{external_customer_id}/credits/ledger_entry", + path_template( + "/customers/external_customer_id/{external_customer_id}/credits/ledger_entry", + external_customer_id=external_customer_id, + ), body=maybe_transform( { "amount": amount, @@ -1972,6 +2140,7 @@ def create_entry_by_external_id( "description": description, "effective_date": effective_date, "expiry_date": expiry_date, + "filters": filters, "invoice_settings": invoice_settings, "metadata": metadata, "per_unit_cost_basis": per_unit_cost_basis, @@ -1996,15 +2165,15 @@ def create_entry_by_external_id( def list_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, - created_at_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - currency: Optional[str] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - entry_status: Optional[Literal["committed", "pending"]] | NotGiven = NOT_GIVEN, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + currency: Optional[str] | Omit = omit, + cursor: Optional[str] | Omit = omit, + entry_status: Optional[Literal["committed", "pending"]] | Omit = omit, entry_type: Optional[ Literal[ "increment", @@ -2016,24 +2185,24 @@ def list_by_external_id( "amendment", ] ] - | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - minimum_amount: Optional[str] | NotGiven = NOT_GIVEN, + | Omit = omit, + limit: int | Omit = omit, + minimum_amount: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[LedgerListByExternalIDResponse]: """ The credits ledger provides _auditing_ functionality over Orb's credits system with a list of actions that have taken place to modify a customer's credit - balance. This [paginated endpoint](../reference/pagination) lists these entries, - starting from the most recent ledger entry. + balance. This [paginated endpoint](/api-reference/pagination) lists these + entries, starting from the most recent ledger entry. More details on using Orb's real-time credit feature are - [here](../guides/product-catalog/prepurchase.md). + [here](/product-catalog/prepurchase). There are four major types of modifications to credit balance, detailed below. @@ -2052,11 +2221,9 @@ def list_by_external_id( As usage for a customer is reported into Orb, credits may be deducted according to the customer's plan configuration. An automated deduction of this type will - result in a ledger entry, also with a starting and ending balance. In order to - provide better tracing capabilities for automatic deductions, Orb always - associates each automatic deduction with the `event_id` at the time of - ingestion, used to pinpoint _why_ credit deduction took place and to ensure that - credits are never deducted without an associated usage event. + result in a ledger entry, also with a starting and ending balance. Each day's + usage for a particular price, invoice, and block will be grouped into a single + entry. By default, Orb uses an algorithm that automatically deducts from the _soonest expiring credit block_ first in order to ensure that all credits are utilized @@ -2065,8 +2232,8 @@ def list_by_external_id( deductions take place from a non-expiring credit block. If there are multiple blocks with the same expiration date, Orb will deduct from - the block with the _lower cost basis_ first (e.g. trial credits with a $0 cost - basis before paid credits with a $5.00 cost basis). + the block with the _lower cost basis_ first (e.g. trial credits with a \\$$0 cost + basis before paid credits with a \\$$5.00 cost basis). It's also possible for a single usage event's deduction to _span_ credit blocks. In this case, Orb will deduct from the next block, ending at the credit block @@ -2084,7 +2251,7 @@ def list_by_external_id( Note that for this entry type, `starting_balance` will equal `ending_balance`, and the `amount` represents the balance transferred. The credit block linked to the ledger entry is the source credit block from which there was an expiration - change + change. ## Credits expiry @@ -2130,7 +2297,10 @@ def list_by_external_id( f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" ) return self._get_api_list( - f"/customers/external_customer_id/{external_customer_id}/credits/ledger", + path_template( + "/customers/external_customer_id/{external_customer_id}/credits/ledger", + external_customer_id=external_customer_id, + ), page=SyncPage[LedgerListByExternalIDResponse], options=make_request_options( extra_headers=extra_headers, @@ -2160,25 +2330,40 @@ def list_by_external_id( class AsyncLedger(AsyncAPIResource): + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ + @cached_property def with_raw_response(self) -> AsyncLedgerWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( self, - customer_id: Optional[str], + customer_id: str, *, - created_at_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - currency: Optional[str] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - entry_status: Optional[Literal["committed", "pending"]] | NotGiven = NOT_GIVEN, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + currency: Optional[str] | Omit = omit, + cursor: Optional[str] | Omit = omit, + entry_status: Optional[Literal["committed", "pending"]] | Omit = omit, entry_type: Optional[ Literal[ "increment", @@ -2190,24 +2375,24 @@ def list( "amendment", ] ] - | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - minimum_amount: Optional[str] | NotGiven = NOT_GIVEN, + | Omit = omit, + limit: int | Omit = omit, + minimum_amount: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[LedgerListResponse, AsyncPage[LedgerListResponse]]: """ The credits ledger provides _auditing_ functionality over Orb's credits system with a list of actions that have taken place to modify a customer's credit - balance. This [paginated endpoint](../reference/pagination) lists these entries, - starting from the most recent ledger entry. + balance. This [paginated endpoint](/api-reference/pagination) lists these + entries, starting from the most recent ledger entry. More details on using Orb's real-time credit feature are - [here](../guides/product-catalog/prepurchase.md). + [here](/product-catalog/prepurchase). There are four major types of modifications to credit balance, detailed below. @@ -2226,11 +2411,9 @@ def list( As usage for a customer is reported into Orb, credits may be deducted according to the customer's plan configuration. An automated deduction of this type will - result in a ledger entry, also with a starting and ending balance. In order to - provide better tracing capabilities for automatic deductions, Orb always - associates each automatic deduction with the `event_id` at the time of - ingestion, used to pinpoint _why_ credit deduction took place and to ensure that - credits are never deducted without an associated usage event. + result in a ledger entry, also with a starting and ending balance. Each day's + usage for a particular price, invoice, and block will be grouped into a single + entry. By default, Orb uses an algorithm that automatically deducts from the _soonest expiring credit block_ first in order to ensure that all credits are utilized @@ -2239,8 +2422,8 @@ def list( deductions take place from a non-expiring credit block. If there are multiple blocks with the same expiration date, Orb will deduct from - the block with the _lower cost basis_ first (e.g. trial credits with a $0 cost - basis before paid credits with a $5.00 cost basis). + the block with the _lower cost basis_ first (e.g. trial credits with a \\$$0 cost + basis before paid credits with a \\$$5.00 cost basis). It's also possible for a single usage event's deduction to _span_ credit blocks. In this case, Orb will deduct from the next block, ending at the credit block @@ -2258,7 +2441,7 @@ def list( Note that for this entry type, `starting_balance` will equal `ending_balance`, and the `amount` represents the balance transferred. The credit block linked to the ledger entry is the source credit block from which there was an expiration - change + change. ## Credits expiry @@ -2302,7 +2485,7 @@ def list( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return self._get_api_list( - f"/customers/{customer_id}/credits/ledger", + path_template("/customers/{customer_id}/credits/ledger", customer_id=customer_id), page=AsyncPage[LedgerListResponse], options=make_request_options( extra_headers=extra_headers, @@ -2331,24 +2514,26 @@ def list( @overload async def create_entry( self, - customer_id: Optional[str], + customer_id: str, *, amount: float, entry_type: Literal["increment"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - effective_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - expiry_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + effective_date: Union[str, datetime, None] | Omit = omit, + expiry_date: Union[str, datetime, None] | Omit = omit, + filters: Optional[Iterable[ledger_create_entry_params.AddIncrementCreditLedgerEntryRequestParamsFilter]] + | Omit = omit, invoice_settings: Optional[ledger_create_entry_params.AddIncrementCreditLedgerEntryRequestParamsInvoiceSettings] - | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - per_unit_cost_basis: Optional[str] | NotGiven = NOT_GIVEN, + | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + per_unit_cost_basis: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryResponse: """ @@ -2362,10 +2547,11 @@ async def create_entry( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -2391,8 +2577,9 @@ async def create_entry( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -2401,16 +2588,29 @@ async def create_entry( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -2478,6 +2678,9 @@ async def create_entry( expiry_date: An ISO 8601 format date that denotes when this credit balance should expire. + filters: Optional filter to specify which items this credit block applies to. If not + specified, the block will apply to all items for the pricing unit. + invoice_settings: Passing `invoice_settings` automatically generates an invoice for the newly added credits. If `invoice_settings` is passed, you must specify per_unit_cost_basis, as the calculation of the invoice total is done on that @@ -2487,8 +2690,8 @@ async def create_entry( by setting the value to `null`, and the entire metadata mapping can be cleared by setting `metadata` to `null`. - per_unit_cost_basis: Can only be specified when entry_type=increment. How much, in USD, a customer - paid for a single credit in this block + per_unit_cost_basis: Can only be specified when entry_type=increment. How much, in the customer's + currency, a customer paid for a single credit in this block extra_headers: Send extra headers @@ -2505,19 +2708,19 @@ async def create_entry( @overload async def create_entry( self, - customer_id: Optional[str], + customer_id: str, *, amount: float, entry_type: Literal["decrement"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryResponse: """ @@ -2531,10 +2734,11 @@ async def create_entry( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -2560,8 +2764,9 @@ async def create_entry( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -2570,16 +2775,29 @@ async def create_entry( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -2661,22 +2879,22 @@ async def create_entry( @overload async def create_entry( self, - customer_id: Optional[str], + customer_id: str, *, entry_type: Literal["expiration_change"], - expiry_date: Union[str, datetime, None], target_expiry_date: Union[str, date], - amount: Optional[float] | NotGiven = NOT_GIVEN, - block_id: Optional[str] | NotGiven = NOT_GIVEN, - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + amount: Optional[float] | Omit = omit, + block_id: Optional[str] | Omit = omit, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + expiry_date: Union[str, datetime, None] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryResponse: """ @@ -2690,10 +2908,11 @@ async def create_entry( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -2719,8 +2938,9 @@ async def create_entry( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -2729,16 +2949,29 @@ async def create_entry( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -2791,11 +3024,9 @@ async def create_entry( return to the customer, up to the block's initial balance. Args: - expiry_date: An ISO 8601 format date that identifies the origination credit block to expire - - target_expiry_date: A future date (specified in YYYY-MM-DD format) used for expiration change, - denoting when credits transferred (as part of a partial block expiration) should - expire. + target_expiry_date: A date (specified in YYYY-MM-DD format) used for expiration change, denoting + when credits transferred (as part of a partial block expiration) should expire. + This date must be on or after the effective date of the credit block. amount: The number of credits to effect. Note that this is required for increment, decrement, void, or undo operations. @@ -2810,6 +3041,8 @@ async def create_entry( For example, this can be used to note an increment refers to trial credits, or for noting corrections as a result of an incident, etc. + expiry_date: An ISO 8601 format date that identifies the origination credit block to expire + 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`. @@ -2829,21 +3062,21 @@ async def create_entry( @overload async def create_entry( self, - customer_id: Optional[str], + customer_id: str, *, amount: float, block_id: str, entry_type: Literal["void"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - void_reason: Optional[Literal["refund"]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + void_reason: Optional[Literal["refund"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryResponse: """ @@ -2857,10 +3090,11 @@ async def create_entry( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -2886,8 +3120,9 @@ async def create_entry( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -2896,16 +3131,29 @@ async def create_entry( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -2991,20 +3239,20 @@ async def create_entry( @overload async def create_entry( self, - customer_id: Optional[str], + customer_id: str, *, amount: float, block_id: str, entry_type: Literal["amendment"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryResponse: """ @@ -3018,10 +3266,11 @@ async def create_entry( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -3047,8 +3296,9 @@ async def create_entry( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -3057,16 +3307,29 @@ async def create_entry( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -3147,40 +3410,36 @@ async def create_entry( """ ... - @required_args( - ["amount", "entry_type"], - ["amount", "entry_type"], - ["entry_type", "expiry_date", "target_expiry_date"], - ["amount", "block_id", "entry_type"], - ["amount", "block_id", "entry_type"], - ) + @required_args(["amount", "entry_type"], ["entry_type", "target_expiry_date"], ["amount", "block_id", "entry_type"]) async def create_entry( self, - customer_id: Optional[str], + customer_id: str, *, - amount: float | None | NotGiven = NOT_GIVEN, + amount: float | Optional[float] | Omit = omit, entry_type: Literal["increment"] | Literal["decrement"] | Literal["expiration_change"] | Literal["void"] | Literal["amendment"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - effective_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - expiry_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + effective_date: Union[str, datetime, None] | Omit = omit, + expiry_date: Union[str, datetime, None] | Omit = omit, + filters: Optional[Iterable[ledger_create_entry_params.AddIncrementCreditLedgerEntryRequestParamsFilter]] + | Omit = omit, invoice_settings: Optional[ledger_create_entry_params.AddIncrementCreditLedgerEntryRequestParamsInvoiceSettings] - | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - per_unit_cost_basis: Optional[str] | NotGiven = NOT_GIVEN, - target_expiry_date: Union[str, date] | NotGiven = NOT_GIVEN, - block_id: Optional[str] | NotGiven = NOT_GIVEN, - void_reason: Optional[Literal["refund"]] | NotGiven = NOT_GIVEN, + | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + per_unit_cost_basis: Optional[str] | Omit = omit, + target_expiry_date: Union[str, date] | Omit = omit, + block_id: Optional[str] | str | Omit = omit, + void_reason: Optional[Literal["refund"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryResponse: if not customer_id: @@ -3188,7 +3447,7 @@ async def create_entry( return cast( LedgerCreateEntryResponse, await self._post( - f"/customers/{customer_id}/credits/ledger_entry", + path_template("/customers/{customer_id}/credits/ledger_entry", customer_id=customer_id), body=await async_maybe_transform( { "amount": amount, @@ -3197,6 +3456,7 @@ async def create_entry( "description": description, "effective_date": effective_date, "expiry_date": expiry_date, + "filters": filters, "invoice_settings": invoice_settings, "metadata": metadata, "per_unit_cost_basis": per_unit_cost_basis, @@ -3222,26 +3482,30 @@ async def create_entry( @overload async def create_entry_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, amount: float, entry_type: Literal["increment"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - effective_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - expiry_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + effective_date: Union[str, datetime, None] | Omit = omit, + expiry_date: Union[str, datetime, None] | Omit = omit, + filters: Optional[ + Iterable[ledger_create_entry_by_external_id_params.AddIncrementCreditLedgerEntryRequestParamsFilter] + ] + | Omit = omit, invoice_settings: Optional[ ledger_create_entry_by_external_id_params.AddIncrementCreditLedgerEntryRequestParamsInvoiceSettings ] - | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - per_unit_cost_basis: Optional[str] | NotGiven = NOT_GIVEN, + | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + per_unit_cost_basis: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryByExternalIDResponse: """ @@ -3255,10 +3519,11 @@ async def create_entry_by_external_id( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -3284,8 +3549,9 @@ async def create_entry_by_external_id( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -3294,16 +3560,29 @@ async def create_entry_by_external_id( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -3371,6 +3650,9 @@ async def create_entry_by_external_id( expiry_date: An ISO 8601 format date that denotes when this credit balance should expire. + filters: Optional filter to specify which items this credit block applies to. If not + specified, the block will apply to all items for the pricing unit. + invoice_settings: Passing `invoice_settings` automatically generates an invoice for the newly added credits. If `invoice_settings` is passed, you must specify per_unit_cost_basis, as the calculation of the invoice total is done on that @@ -3380,8 +3662,8 @@ async def create_entry_by_external_id( by setting the value to `null`, and the entire metadata mapping can be cleared by setting `metadata` to `null`. - per_unit_cost_basis: Can only be specified when entry_type=increment. How much, in USD, a customer - paid for a single credit in this block + per_unit_cost_basis: Can only be specified when entry_type=increment. How much, in the customer's + currency, a customer paid for a single credit in this block extra_headers: Send extra headers @@ -3398,19 +3680,19 @@ async def create_entry_by_external_id( @overload async def create_entry_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, amount: float, entry_type: Literal["decrement"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryByExternalIDResponse: """ @@ -3424,10 +3706,11 @@ async def create_entry_by_external_id( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -3453,8 +3736,9 @@ async def create_entry_by_external_id( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -3463,16 +3747,29 @@ async def create_entry_by_external_id( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -3554,22 +3851,22 @@ async def create_entry_by_external_id( @overload async def create_entry_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, entry_type: Literal["expiration_change"], - expiry_date: Union[str, datetime, None], target_expiry_date: Union[str, date], - amount: Optional[float] | NotGiven = NOT_GIVEN, - block_id: Optional[str] | NotGiven = NOT_GIVEN, - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + amount: Optional[float] | Omit = omit, + block_id: Optional[str] | Omit = omit, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + expiry_date: Union[str, datetime, None] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryByExternalIDResponse: """ @@ -3583,10 +3880,11 @@ async def create_entry_by_external_id( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -3612,8 +3910,9 @@ async def create_entry_by_external_id( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -3622,16 +3921,29 @@ async def create_entry_by_external_id( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -3684,11 +3996,9 @@ async def create_entry_by_external_id( return to the customer, up to the block's initial balance. Args: - expiry_date: An ISO 8601 format date that identifies the origination credit block to expire - - target_expiry_date: A future date (specified in YYYY-MM-DD format) used for expiration change, - denoting when credits transferred (as part of a partial block expiration) should - expire. + target_expiry_date: A date (specified in YYYY-MM-DD format) used for expiration change, denoting + when credits transferred (as part of a partial block expiration) should expire. + This date must be on or after the effective date of the credit block. amount: The number of credits to effect. Note that this is required for increment, decrement, void, or undo operations. @@ -3703,6 +4013,8 @@ async def create_entry_by_external_id( For example, this can be used to note an increment refers to trial credits, or for noting corrections as a result of an incident, etc. + expiry_date: An ISO 8601 format date that identifies the origination credit block to expire + 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`. @@ -3722,21 +4034,21 @@ async def create_entry_by_external_id( @overload async def create_entry_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, amount: float, block_id: str, entry_type: Literal["void"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - void_reason: Optional[Literal["refund"]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + void_reason: Optional[Literal["refund"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryByExternalIDResponse: """ @@ -3750,10 +4062,11 @@ async def create_entry_by_external_id( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -3779,8 +4092,9 @@ async def create_entry_by_external_id( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -3789,16 +4103,29 @@ async def create_entry_by_external_id( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -3884,20 +4211,20 @@ async def create_entry_by_external_id( @overload async def create_entry_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, amount: float, block_id: str, entry_type: Literal["amendment"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryByExternalIDResponse: """ @@ -3911,10 +4238,11 @@ async def create_entry_by_external_id( will return a credit block that represents the changes (i.e. balance changes or transfers). 2. A ledger entry will be added to the credits ledger for this customer, and - therefore returned in the [View Credits Ledger](fetch-customer-credits) - response as well as serialized in the response to this request. In the case - of deductions without a specified block, multiple ledger entries may be - created if the deduction spans credit blocks. + therefore returned in the + [View Credits Ledger](fetch-customer-credits-ledger) response as well as + serialized in the response to this request. In the case of deductions without + a specified block, multiple ledger entries may be created if the deduction + spans credit blocks. 3. If `invoice_settings` is specified, an invoice will be created that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). @@ -3940,8 +4268,9 @@ async def create_entry_by_external_id( } ``` - Note that by default, Orb will always first increment any _negative_ balance in - existing blocks before adding the remaining amount to the desired credit block. + Note that an `increment` entry always creates a new credit block (defined by the + optional `effective_date` and `expiry_date`); it never modifies an existing + block. ### Invoicing for credits @@ -3950,16 +4279,29 @@ async def create_entry_by_external_id( also generate a one-off invoice for the customer for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, since the total charges on the invoice are calculated by multiplying the cost basis with the number of - credit units added. + credit units added. If you invoice or handle payment of credits outside of Orb + (i.e. marketplace customers), set `mark_as_paid` in the `invoice_settings` to + `true` to prevent duplicate invoicing effects. + + - if `per_unit_cost_basis` is greater than zero, an invoice will be generated + and `invoice_settings` must be included + - if `invoice_settings` is passed, one of either `custom_due_date` or + `net_terms` is required to determine the due date ## Deducting Credits Orb allows you to deduct credits from a customer by creating an entry of type - `decrement`. Orb matches the algorithm for automatic deductions for determining - which credit blocks to decrement from. In the case that the deduction leads to - multiple ledger entries, the response from this endpoint will be the final - deduction. Orb also optionally allows specifying a description to assist with - auditing. + `decrement`. A `decrement` entry records credits as usage and immediately + recognizes revenue at the block's `per_unit_cost_basis`. + + For most credit removals, use `void` (no revenue impact) or `expiration_change` + (revenue recognized on expiration) instead. Only use `decrement` when credits + were genuinely consumed outside of normal event ingestion. + + Orb matches the algorithm for automatic deductions for determining which credit + blocks to decrement from. In the case that the deduction leads to multiple + ledger entries, the response from this endpoint will be the final deduction. Orb + also optionally allows specifying a description to assist with auditing. The following snippet illustrates a sample request body to decrement credits. @@ -4040,42 +4382,40 @@ async def create_entry_by_external_id( """ ... - @required_args( - ["amount", "entry_type"], - ["amount", "entry_type"], - ["entry_type", "expiry_date", "target_expiry_date"], - ["amount", "block_id", "entry_type"], - ["amount", "block_id", "entry_type"], - ) + @required_args(["amount", "entry_type"], ["entry_type", "target_expiry_date"], ["amount", "block_id", "entry_type"]) async def create_entry_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, - amount: float | None | NotGiven = NOT_GIVEN, + amount: float | Optional[float] | Omit = omit, entry_type: Literal["increment"] | Literal["decrement"] | Literal["expiration_change"] | Literal["void"] | Literal["amendment"], - currency: Optional[str] | NotGiven = NOT_GIVEN, - description: Optional[str] | NotGiven = NOT_GIVEN, - effective_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - expiry_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + effective_date: Union[str, datetime, None] | Omit = omit, + expiry_date: Union[str, datetime, None] | Omit = omit, + filters: Optional[ + Iterable[ledger_create_entry_by_external_id_params.AddIncrementCreditLedgerEntryRequestParamsFilter] + ] + | Omit = omit, invoice_settings: Optional[ ledger_create_entry_by_external_id_params.AddIncrementCreditLedgerEntryRequestParamsInvoiceSettings ] - | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - per_unit_cost_basis: Optional[str] | NotGiven = NOT_GIVEN, - target_expiry_date: Union[str, date] | NotGiven = NOT_GIVEN, - block_id: Optional[str] | NotGiven = NOT_GIVEN, - void_reason: Optional[Literal["refund"]] | NotGiven = NOT_GIVEN, + | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + per_unit_cost_basis: Optional[str] | Omit = omit, + target_expiry_date: Union[str, date] | Omit = omit, + block_id: Optional[str] | str | Omit = omit, + void_reason: Optional[Literal["refund"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> LedgerCreateEntryByExternalIDResponse: if not external_customer_id: @@ -4085,7 +4425,10 @@ async def create_entry_by_external_id( return cast( LedgerCreateEntryByExternalIDResponse, await self._post( - f"/customers/external_customer_id/{external_customer_id}/credits/ledger_entry", + path_template( + "/customers/external_customer_id/{external_customer_id}/credits/ledger_entry", + external_customer_id=external_customer_id, + ), body=await async_maybe_transform( { "amount": amount, @@ -4094,6 +4437,7 @@ async def create_entry_by_external_id( "description": description, "effective_date": effective_date, "expiry_date": expiry_date, + "filters": filters, "invoice_settings": invoice_settings, "metadata": metadata, "per_unit_cost_basis": per_unit_cost_basis, @@ -4118,15 +4462,15 @@ async def create_entry_by_external_id( def list_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, - created_at_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - currency: Optional[str] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - entry_status: Optional[Literal["committed", "pending"]] | NotGiven = NOT_GIVEN, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + currency: Optional[str] | Omit = omit, + cursor: Optional[str] | Omit = omit, + entry_status: Optional[Literal["committed", "pending"]] | Omit = omit, entry_type: Optional[ Literal[ "increment", @@ -4138,24 +4482,24 @@ def list_by_external_id( "amendment", ] ] - | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - minimum_amount: Optional[str] | NotGiven = NOT_GIVEN, + | Omit = omit, + limit: int | Omit = omit, + minimum_amount: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[LedgerListByExternalIDResponse, AsyncPage[LedgerListByExternalIDResponse]]: """ The credits ledger provides _auditing_ functionality over Orb's credits system with a list of actions that have taken place to modify a customer's credit - balance. This [paginated endpoint](../reference/pagination) lists these entries, - starting from the most recent ledger entry. + balance. This [paginated endpoint](/api-reference/pagination) lists these + entries, starting from the most recent ledger entry. More details on using Orb's real-time credit feature are - [here](../guides/product-catalog/prepurchase.md). + [here](/product-catalog/prepurchase). There are four major types of modifications to credit balance, detailed below. @@ -4174,11 +4518,9 @@ def list_by_external_id( As usage for a customer is reported into Orb, credits may be deducted according to the customer's plan configuration. An automated deduction of this type will - result in a ledger entry, also with a starting and ending balance. In order to - provide better tracing capabilities for automatic deductions, Orb always - associates each automatic deduction with the `event_id` at the time of - ingestion, used to pinpoint _why_ credit deduction took place and to ensure that - credits are never deducted without an associated usage event. + result in a ledger entry, also with a starting and ending balance. Each day's + usage for a particular price, invoice, and block will be grouped into a single + entry. By default, Orb uses an algorithm that automatically deducts from the _soonest expiring credit block_ first in order to ensure that all credits are utilized @@ -4187,8 +4529,8 @@ def list_by_external_id( deductions take place from a non-expiring credit block. If there are multiple blocks with the same expiration date, Orb will deduct from - the block with the _lower cost basis_ first (e.g. trial credits with a $0 cost - basis before paid credits with a $5.00 cost basis). + the block with the _lower cost basis_ first (e.g. trial credits with a \\$$0 cost + basis before paid credits with a \\$$5.00 cost basis). It's also possible for a single usage event's deduction to _span_ credit blocks. In this case, Orb will deduct from the next block, ending at the credit block @@ -4206,7 +4548,7 @@ def list_by_external_id( Note that for this entry type, `starting_balance` will equal `ending_balance`, and the `amount` represents the balance transferred. The credit block linked to the ledger entry is the source credit block from which there was an expiration - change + change. ## Credits expiry @@ -4252,7 +4594,10 @@ def list_by_external_id( f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" ) return self._get_api_list( - f"/customers/external_customer_id/{external_customer_id}/credits/ledger", + path_template( + "/customers/external_customer_id/{external_customer_id}/credits/ledger", + external_customer_id=external_customer_id, + ), page=AsyncPage[LedgerListByExternalIDResponse], options=make_request_options( extra_headers=extra_headers, diff --git a/src/orb/resources/customers/credits/top_ups.py b/src/orb/resources/customers/credits/top_ups.py index 98e355ca..52d2ac9f 100644 --- a/src/orb/resources/customers/credits/top_ups.py +++ b/src/orb/resources/customers/credits/top_ups.py @@ -2,65 +2,76 @@ from __future__ import annotations -from typing import Optional +from typing import Union, Optional +from datetime import datetime from typing_extensions import Literal import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven -from ...._utils import ( - maybe_transform, - async_maybe_transform, -) +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import path_template, 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 ....pagination import SyncPage, AsyncPage -from ...._base_client import ( - AsyncPaginator, - make_request_options, -) +from ...._base_client import AsyncPaginator, make_request_options from ....types.customers.credits import ( - TopUpListResponse, - TopUpCreateResponse, - TopUpListByExternalIDResponse, - TopUpCreateByExternalIDResponse, top_up_list_params, top_up_create_params, top_up_list_by_external_id_params, top_up_create_by_external_id_params, ) +from ....types.customers.credits.top_up_list_response import TopUpListResponse +from ....types.customers.credits.top_up_create_response import TopUpCreateResponse +from ....types.customers.credits.top_up_list_by_external_id_response import TopUpListByExternalIDResponse +from ....types.customers.credits.top_up_create_by_external_id_response import TopUpCreateByExternalIDResponse __all__ = ["TopUps", "AsyncTopUps"] class TopUps(SyncAPIResource): + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ + @cached_property def with_raw_response(self) -> TopUpsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( self, - customer_id: Optional[str], + customer_id: str, *, amount: str, currency: str, invoice_settings: top_up_create_params.InvoiceSettings, per_unit_cost_basis: str, threshold: str, - expires_after: Optional[int] | NotGiven = NOT_GIVEN, - expires_after_unit: Optional[Literal["day", "month"]] | NotGiven = NOT_GIVEN, + active_from: Union[str, datetime, None] | Omit = omit, + expires_after: Optional[int] | Omit = omit, + expires_after_unit: Optional[Literal["day", "month"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> TopUpCreateResponse: """ @@ -85,6 +96,9 @@ def create( threshold: The threshold at which to trigger the top-up. If the balance is at or below this threshold, the top-up will be triggered. + active_from: The date from which the top-up is active. If unspecified, the top-up is active + immediately. This should not be more than 10 days in the past. + expires_after: The number of days or months after which the top-up expires. If unspecified, it does not expire. @@ -103,7 +117,7 @@ def create( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return self._post( - f"/customers/{customer_id}/credits/top_ups", + path_template("/customers/{customer_id}/credits/top_ups", customer_id=customer_id), body=maybe_transform( { "amount": amount, @@ -111,6 +125,7 @@ def create( "invoice_settings": invoice_settings, "per_unit_cost_basis": per_unit_cost_basis, "threshold": threshold, + "active_from": active_from, "expires_after": expires_after, "expires_after_unit": expires_after_unit, }, @@ -128,16 +143,16 @@ def create( def list( self, - customer_id: Optional[str], + customer_id: str, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[TopUpListResponse]: """List top-ups @@ -160,7 +175,7 @@ def list( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return self._get_api_list( - f"/customers/{customer_id}/credits/top_ups", + path_template("/customers/{customer_id}/credits/top_ups", customer_id=customer_id), page=SyncPage[TopUpListResponse], options=make_request_options( extra_headers=extra_headers, @@ -182,17 +197,18 @@ def delete( self, top_up_id: str, *, - customer_id: Optional[str], + customer_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, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> None: """ - Delete top-up + This deactivates the top-up and voids any invoices associated with pending + credit blocks purchased through the top-up. Args: extra_headers: Send extra headers @@ -211,7 +227,9 @@ def delete( raise ValueError(f"Expected a non-empty value for `top_up_id` but received {top_up_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/customers/{customer_id}/credits/top_ups/{top_up_id}", + path_template( + "/customers/{customer_id}/credits/top_ups/{top_up_id}", customer_id=customer_id, top_up_id=top_up_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -224,21 +242,22 @@ def delete( def create_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, amount: str, currency: str, invoice_settings: top_up_create_by_external_id_params.InvoiceSettings, per_unit_cost_basis: str, threshold: str, - expires_after: Optional[int] | NotGiven = NOT_GIVEN, - expires_after_unit: Optional[Literal["day", "month"]] | NotGiven = NOT_GIVEN, + active_from: Union[str, datetime, None] | Omit = omit, + expires_after: Optional[int] | Omit = omit, + expires_after_unit: Optional[Literal["day", "month"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> TopUpCreateByExternalIDResponse: """ @@ -263,6 +282,9 @@ def create_by_external_id( threshold: The threshold at which to trigger the top-up. If the balance is at or below this threshold, the top-up will be triggered. + active_from: The date from which the top-up is active. If unspecified, the top-up is active + immediately. This should not be more than 10 days in the past. + expires_after: The number of days or months after which the top-up expires. If unspecified, it does not expire. @@ -283,7 +305,10 @@ def create_by_external_id( f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" ) return self._post( - f"/customers/external_customer_id/{external_customer_id}/credits/top_ups", + path_template( + "/customers/external_customer_id/{external_customer_id}/credits/top_ups", + external_customer_id=external_customer_id, + ), body=maybe_transform( { "amount": amount, @@ -291,6 +316,7 @@ def create_by_external_id( "invoice_settings": invoice_settings, "per_unit_cost_basis": per_unit_cost_basis, "threshold": threshold, + "active_from": active_from, "expires_after": expires_after, "expires_after_unit": expires_after_unit, }, @@ -310,17 +336,18 @@ def delete_by_external_id( self, top_up_id: str, *, - external_customer_id: Optional[str], + external_customer_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, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> None: """ - Delete top-up by external ID + This deactivates the top-up and voids any invoices associated with pending + credit blocks purchased through the top-up. Args: extra_headers: Send extra headers @@ -341,7 +368,11 @@ def delete_by_external_id( raise ValueError(f"Expected a non-empty value for `top_up_id` but received {top_up_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/customers/external_customer_id/{external_customer_id}/credits/top_ups/{top_up_id}", + path_template( + "/customers/external_customer_id/{external_customer_id}/credits/top_ups/{top_up_id}", + external_customer_id=external_customer_id, + top_up_id=top_up_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -354,16 +385,16 @@ def delete_by_external_id( def list_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[TopUpListByExternalIDResponse]: """List top-ups by external ID @@ -388,7 +419,10 @@ def list_by_external_id( f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" ) return self._get_api_list( - f"/customers/external_customer_id/{external_customer_id}/credits/top_ups", + path_template( + "/customers/external_customer_id/{external_customer_id}/credits/top_ups", + external_customer_id=external_customer_id, + ), page=SyncPage[TopUpListByExternalIDResponse], options=make_request_options( extra_headers=extra_headers, @@ -408,31 +442,47 @@ def list_by_external_id( class AsyncTopUps(AsyncAPIResource): + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ + @cached_property def with_raw_response(self) -> AsyncTopUpsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( self, - customer_id: Optional[str], + customer_id: str, *, amount: str, currency: str, invoice_settings: top_up_create_params.InvoiceSettings, per_unit_cost_basis: str, threshold: str, - expires_after: Optional[int] | NotGiven = NOT_GIVEN, - expires_after_unit: Optional[Literal["day", "month"]] | NotGiven = NOT_GIVEN, + active_from: Union[str, datetime, None] | Omit = omit, + expires_after: Optional[int] | Omit = omit, + expires_after_unit: Optional[Literal["day", "month"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> TopUpCreateResponse: """ @@ -457,6 +507,9 @@ async def create( threshold: The threshold at which to trigger the top-up. If the balance is at or below this threshold, the top-up will be triggered. + active_from: The date from which the top-up is active. If unspecified, the top-up is active + immediately. This should not be more than 10 days in the past. + expires_after: The number of days or months after which the top-up expires. If unspecified, it does not expire. @@ -475,7 +528,7 @@ async def create( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return await self._post( - f"/customers/{customer_id}/credits/top_ups", + path_template("/customers/{customer_id}/credits/top_ups", customer_id=customer_id), body=await async_maybe_transform( { "amount": amount, @@ -483,6 +536,7 @@ async def create( "invoice_settings": invoice_settings, "per_unit_cost_basis": per_unit_cost_basis, "threshold": threshold, + "active_from": active_from, "expires_after": expires_after, "expires_after_unit": expires_after_unit, }, @@ -500,16 +554,16 @@ async def create( def list( self, - customer_id: Optional[str], + customer_id: str, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[TopUpListResponse, AsyncPage[TopUpListResponse]]: """List top-ups @@ -532,7 +586,7 @@ def list( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return self._get_api_list( - f"/customers/{customer_id}/credits/top_ups", + path_template("/customers/{customer_id}/credits/top_ups", customer_id=customer_id), page=AsyncPage[TopUpListResponse], options=make_request_options( extra_headers=extra_headers, @@ -554,17 +608,18 @@ async def delete( self, top_up_id: str, *, - customer_id: Optional[str], + customer_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, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> None: """ - Delete top-up + This deactivates the top-up and voids any invoices associated with pending + credit blocks purchased through the top-up. Args: extra_headers: Send extra headers @@ -583,7 +638,9 @@ async def delete( raise ValueError(f"Expected a non-empty value for `top_up_id` but received {top_up_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/customers/{customer_id}/credits/top_ups/{top_up_id}", + path_template( + "/customers/{customer_id}/credits/top_ups/{top_up_id}", customer_id=customer_id, top_up_id=top_up_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -596,21 +653,22 @@ async def delete( async def create_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, amount: str, currency: str, invoice_settings: top_up_create_by_external_id_params.InvoiceSettings, per_unit_cost_basis: str, threshold: str, - expires_after: Optional[int] | NotGiven = NOT_GIVEN, - expires_after_unit: Optional[Literal["day", "month"]] | NotGiven = NOT_GIVEN, + active_from: Union[str, datetime, None] | Omit = omit, + expires_after: Optional[int] | Omit = omit, + expires_after_unit: Optional[Literal["day", "month"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> TopUpCreateByExternalIDResponse: """ @@ -635,6 +693,9 @@ async def create_by_external_id( threshold: The threshold at which to trigger the top-up. If the balance is at or below this threshold, the top-up will be triggered. + active_from: The date from which the top-up is active. If unspecified, the top-up is active + immediately. This should not be more than 10 days in the past. + expires_after: The number of days or months after which the top-up expires. If unspecified, it does not expire. @@ -655,7 +716,10 @@ async def create_by_external_id( f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" ) return await self._post( - f"/customers/external_customer_id/{external_customer_id}/credits/top_ups", + path_template( + "/customers/external_customer_id/{external_customer_id}/credits/top_ups", + external_customer_id=external_customer_id, + ), body=await async_maybe_transform( { "amount": amount, @@ -663,6 +727,7 @@ async def create_by_external_id( "invoice_settings": invoice_settings, "per_unit_cost_basis": per_unit_cost_basis, "threshold": threshold, + "active_from": active_from, "expires_after": expires_after, "expires_after_unit": expires_after_unit, }, @@ -682,17 +747,18 @@ async def delete_by_external_id( self, top_up_id: str, *, - external_customer_id: Optional[str], + external_customer_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, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> None: """ - Delete top-up by external ID + This deactivates the top-up and voids any invoices associated with pending + credit blocks purchased through the top-up. Args: extra_headers: Send extra headers @@ -713,7 +779,11 @@ async def delete_by_external_id( raise ValueError(f"Expected a non-empty value for `top_up_id` but received {top_up_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/customers/external_customer_id/{external_customer_id}/credits/top_ups/{top_up_id}", + path_template( + "/customers/external_customer_id/{external_customer_id}/credits/top_ups/{top_up_id}", + external_customer_id=external_customer_id, + top_up_id=top_up_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -726,16 +796,16 @@ async def delete_by_external_id( def list_by_external_id( self, - external_customer_id: Optional[str], + external_customer_id: str, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[TopUpListByExternalIDResponse, AsyncPage[TopUpListByExternalIDResponse]]: """List top-ups by external ID @@ -760,7 +830,10 @@ def list_by_external_id( f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" ) return self._get_api_list( - f"/customers/external_customer_id/{external_customer_id}/credits/top_ups", + path_template( + "/customers/external_customer_id/{external_customer_id}/credits/top_ups", + external_customer_id=external_customer_id, + ), page=AsyncPage[TopUpListByExternalIDResponse], options=make_request_options( extra_headers=extra_headers, diff --git a/src/orb/resources/customers/customers.py b/src/orb/resources/customers/customers.py index 33510b78..48a74719 100644 --- a/src/orb/resources/customers/customers.py +++ b/src/orb/resources/customers/customers.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, List, Union, Optional +from typing import Dict, Union, Optional from datetime import datetime from typing_extensions import Literal @@ -17,22 +17,20 @@ CostsWithStreamingResponse, AsyncCostsWithStreamingResponse, ) -from .usage import ( - Usage, - AsyncUsage, - UsageWithRawResponse, - AsyncUsageWithRawResponse, - UsageWithStreamingResponse, - AsyncUsageWithStreamingResponse, -) from ...types import ( - Customer, customer_list_params, customer_create_params, customer_update_params, customer_update_by_external_id_params, ) -from .credits import ( +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import path_template, 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 ...pagination import SyncPage, AsyncPage +from ..._base_client import AsyncPaginator, make_request_options +from .credits.credits import ( Credits, AsyncCredits, CreditsWithRawResponse, @@ -40,20 +38,7 @@ CreditsWithStreamingResponse, AsyncCreditsWithStreamingResponse, ) -from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, 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 ...pagination import SyncPage, AsyncPage -from ..._base_client import ( - AsyncPaginator, - make_request_options, -) -from .credits.credits import Credits, AsyncCredits +from ...types.customer import Customer from .balance_transactions import ( BalanceTransactions, AsyncBalanceTransactions, @@ -62,33 +47,97 @@ BalanceTransactionsWithStreamingResponse, AsyncBalanceTransactionsWithStreamingResponse, ) +from ...types.address_input_param import AddressInputParam +from ...types.shared_params.customer_tax_id import CustomerTaxID +from ...types.customer_hierarchy_config_param import CustomerHierarchyConfigParam +from ...types.new_reporting_configuration_param import NewReportingConfigurationParam +from ...types.new_accounting_sync_configuration_param import NewAccountingSyncConfigurationParam __all__ = ["Customers", "AsyncCustomers"] class Customers(SyncAPIResource): + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + @cached_property def costs(self) -> Costs: - return Costs(self._client) + """ + A customer is a buyer of your products, and the other party to the billing relationship. - @cached_property - def usage(self) -> Usage: - return Usage(self._client) + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + return Costs(self._client) @cached_property def credits(self) -> Credits: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return Credits(self._client) @cached_property def balance_transactions(self) -> BalanceTransactions: + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ return BalanceTransactions(self._client) @cached_property def with_raw_response(self) -> CustomersWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -96,43 +145,48 @@ def create( *, email: str, name: str, - accounting_sync_configuration: Optional[customer_create_params.AccountingSyncConfiguration] - | NotGiven = NOT_GIVEN, - additional_emails: Optional[List[str]] | NotGiven = NOT_GIVEN, - auto_collection: Optional[bool] | NotGiven = NOT_GIVEN, - billing_address: Optional[customer_create_params.BillingAddress] | NotGiven = NOT_GIVEN, - currency: Optional[str] | NotGiven = NOT_GIVEN, - email_delivery: Optional[bool] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - payment_provider: Optional[Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite"]] - | NotGiven = NOT_GIVEN, - 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_id: Optional[customer_create_params.TaxID] | NotGiven = NOT_GIVEN, - timezone: Optional[str] | NotGiven = NOT_GIVEN, + accounting_sync_configuration: Optional[NewAccountingSyncConfigurationParam] | Omit = omit, + additional_emails: Optional[SequenceNotStr[str]] | Omit = omit, + auto_collection: Optional[bool] | Omit = omit, + auto_issuance: Optional[bool] | Omit = omit, + billing_address: Optional[AddressInputParam] | Omit = omit, + currency: Optional[str] | Omit = omit, + email_delivery: Optional[bool] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + hierarchy: Optional[CustomerHierarchyConfigParam] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + payment_configuration: Optional[customer_create_params.PaymentConfiguration] | Omit = omit, + payment_provider: Optional[ + Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite", "adyen"] + ] + | Omit = omit, + payment_provider_id: Optional[str] | Omit = omit, + reporting_configuration: Optional[NewReportingConfigurationParam] | Omit = omit, + shipping_address: Optional[AddressInputParam] | Omit = omit, + tax_configuration: Optional[customer_create_params.TaxConfiguration] | Omit = omit, + tax_id: Optional[CustomerTaxID] | Omit = omit, + timezone: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Customer: """ This operation is used to create an Orb customer, who is party to the core - billing relationship. See [Customer](../guides/concepts#customer) for an - overview of the customer resource. + billing relationship. See [Customer](/core-concepts##customer) for an overview + of the customer resource. This endpoint is critical in the following Orb functionality: - Automated charges can be configured by setting `payment_provider` and `payment_provider_id` to automatically issue invoices - - [Customer ID Aliases](../guides/events-and-metrics/customer-aliases) can be - configured by setting `external_customer_id` - - [Timezone localization](../guides/product-catalog/timezones.md) can be - configured on a per-customer basis by setting the `timezone` parameter + - [Customer ID Aliases](/events-and-metrics/customer-aliases) can be configured + by setting `external_customer_id` + - [Timezone localization](/essentials/timezones) can be configured on a + per-customer basis by setting the `timezone` parameter Args: email: A valid customer email, to be used for notifications. When Orb triggers payment @@ -142,12 +196,18 @@ def create( name: The full name of the customer additional_emails: Additional email addresses for this customer. If populated, these email - addresses will be CC'd for customer communications. + addresses will be CC'd for customer communications. The total number of email + addresses (including the primary email) cannot exceed 50. auto_collection: Used to determine if invoices for this customer will automatically attempt to charge a saved payment method, if available. This parameter defaults to `True` when a payment provider is provided on customer creation. + auto_issuance: Used to determine if invoices for this customer will be automatically issued. If + true, invoices will be automatically issued. If false, invoices will require + manual approval. If `null` is specified, the customer's auto issuance setting + will be inherited from the account-level setting. + currency: An ISO 4217 currency string used for the customer's invoices and balance. If not set at creation time, will be set at subscription creation time. @@ -155,10 +215,15 @@ def create( system as an alias for this Customer. Use this field to identify a customer by an existing identifier in your system. + hierarchy: The hierarchical relationships for this customer. + 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`. + payment_configuration: Payment configuration for the customer, applicable when using Orb Invoicing with + a supported payment provider such as Stripe. + payment_provider: This is used for creating charges or invoices in an external system via Orb. When not in test mode, the connection must first be configured in the Orb webapp. @@ -171,86 +236,151 @@ def create( ### Supported Tax ID Countries and Types - | Country | Type | Description | - | -------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | - | Andorra | `ad_nrt` | Andorran NRT number | - | Australia | `au_abn` | Australian Business Number (AU ABN) | - | Australia | `au_arn` | Australian Taxation Office Reference Number | - | Austria | `eu_vat` | European VAT number | - | Belgium | `eu_vat` | European VAT number | - | Brazil | `br_cnpj` | Brazilian CNPJ number | - | Brazil | `br_cpf` | Brazilian CPF number | - | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | - | Bulgaria | `eu_vat` | European VAT number | - | Canada | `ca_bn` | Canadian BN | - | Canada | `ca_gst_hst` | Canadian GST/HST number | - | Canada | `ca_pst_bc` | Canadian PST number (British Columbia) | - | Canada | `ca_pst_mb` | Canadian PST number (Manitoba) | - | Canada | `ca_pst_sk` | Canadian PST number (Saskatchewan) | - | Canada | `ca_qst` | Canadian QST number (Québec) | - | Chile | `cl_tin` | Chilean TIN | - | Croatia | `eu_vat` | European VAT number | - | Cyprus | `eu_vat` | European VAT number | - | Czech Republic | `eu_vat` | European VAT number | - | Denmark | `eu_vat` | European VAT number | - | Egypt | `eg_tin` | Egyptian Tax Identification Number | - | Estonia | `eu_vat` | European VAT number | - | EU | `eu_oss_vat` | European One Stop Shop VAT number for non-Union scheme | - | Finland | `eu_vat` | European VAT number | - | France | `eu_vat` | European VAT number | - | Georgia | `ge_vat` | Georgian VAT | - | Germany | `eu_vat` | European VAT number | - | Greece | `eu_vat` | European VAT number | - | Hong Kong | `hk_br` | Hong Kong BR number | - | Hungary | `eu_vat` | European VAT number | - | Hungary | `hu_tin` | Hungary tax number (adószám) | - | Iceland | `is_vat` | Icelandic VAT | - | India | `in_gst` | Indian GST number | - | Indonesia | `id_npwp` | Indonesian NPWP number | - | Ireland | `eu_vat` | European VAT number | - | Israel | `il_vat` | Israel VAT | - | Italy | `eu_vat` | European VAT number | - | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | - | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | - | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | - | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | - | Latvia | `eu_vat` | European VAT number | - | Liechtenstein | `li_uid` | Liechtensteinian UID number | - | Lithuania | `eu_vat` | European VAT number | - | Luxembourg | `eu_vat` | European VAT number | - | Malaysia | `my_frp` | Malaysian FRP number | - | Malaysia | `my_itn` | Malaysian ITN | - | Malaysia | `my_sst` | Malaysian SST number | - | Malta | `eu_vat ` | European VAT number | - | Mexico | `mx_rfc` | Mexican RFC number | - | Netherlands | `eu_vat` | European VAT number | - | New Zealand | `nz_gst` | New Zealand GST number | - | Norway | `no_vat` | Norwegian VAT number | - | Philippines | `ph_tin ` | Philippines Tax Identification Number | - | Poland | `eu_vat` | European VAT number | - | Portugal | `eu_vat` | European VAT number | - | Romania | `eu_vat` | European VAT number | - | Russia | `ru_inn` | Russian INN | - | Russia | `ru_kpp` | Russian KPP | - | Saudi Arabia | `sg_gst` | Singaporean GST | - | Singapore | `sg_uen` | Singaporean UEN | - | Slovakia | `eu_vat` | European VAT number | - | Slovenia | `eu_vat` | European VAT number | - | Slovenia | `si_tin` | Slovenia tax number (davčna številka) | - | South Africa | `za_vat` | South African VAT number | - | South Korea | `kr_brn` | Korean BRN | - | Spain | `es_cif` | Spanish NIF number (previously Spanish CIF number) | - | Spain | `eu_vat` | European VAT number | - | Sweden | `eu_vat` | European VAT number | - | Switzerland | `ch_vat` | Switzerland VAT number | - | Taiwan | `tw_vat` | Taiwanese VAT | - | Thailand | `th_vat` | Thai VAT | - | Turkey | `tr_tin` | Turkish Tax Identification Number | - | Ukraine | `ua_vat` | Ukrainian VAT | - | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | - | United Kingdom | `eu_vat` | Northern Ireland VAT number | - | United Kingdom | `gb_vat` | United Kingdom VAT number | - | United States | `us_ein` | United States EIN | + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | timezone: A timezone identifier from the IANA timezone database, such as `"America/Los_Angeles"`. This defaults to your account's timezone if not set. @@ -275,15 +405,19 @@ def create( "accounting_sync_configuration": accounting_sync_configuration, "additional_emails": additional_emails, "auto_collection": auto_collection, + "auto_issuance": auto_issuance, "billing_address": billing_address, "currency": currency, "email_delivery": email_delivery, "external_customer_id": external_customer_id, + "hierarchy": hierarchy, "metadata": metadata, + "payment_configuration": payment_configuration, "payment_provider": payment_provider, "payment_provider_id": payment_provider_id, "reporting_configuration": reporting_configuration, "shipping_address": shipping_address, + "tax_configuration": tax_configuration, "tax_id": tax_id, "timezone": timezone, }, @@ -303,53 +437,76 @@ def update( self, customer_id: str, *, - accounting_sync_configuration: Optional[customer_update_params.AccountingSyncConfiguration] - | NotGiven = NOT_GIVEN, - additional_emails: Optional[List[str]] | NotGiven = NOT_GIVEN, - auto_collection: Optional[bool] | NotGiven = NOT_GIVEN, - billing_address: Optional[customer_update_params.BillingAddress] | NotGiven = NOT_GIVEN, - currency: Optional[str] | NotGiven = NOT_GIVEN, - email: Optional[str] | NotGiven = NOT_GIVEN, - email_delivery: Optional[bool] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - payment_provider: Optional[Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite"]] - | NotGiven = NOT_GIVEN, - 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_id: Optional[customer_update_params.TaxID] | NotGiven = NOT_GIVEN, + accounting_sync_configuration: Optional[NewAccountingSyncConfigurationParam] | Omit = omit, + additional_emails: Optional[SequenceNotStr[str]] | Omit = omit, + auto_collection: Optional[bool] | Omit = omit, + auto_issuance: Optional[bool] | Omit = omit, + billing_address: Optional[AddressInputParam] | Omit = omit, + currency: Optional[str] | Omit = omit, + default_payment_method_id: Optional[str] | Omit = omit, + email: Optional[str] | Omit = omit, + email_delivery: Optional[bool] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + hierarchy: Optional[CustomerHierarchyConfigParam] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + name: Optional[str] | Omit = omit, + payment_configuration: Optional[customer_update_params.PaymentConfiguration] | Omit = omit, + payment_provider: Optional[ + Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite", "adyen"] + ] + | Omit = omit, + payment_provider_id: Optional[str] | Omit = omit, + reporting_configuration: Optional[NewReportingConfigurationParam] | Omit = omit, + shipping_address: Optional[AddressInputParam] | Omit = omit, + tax_configuration: Optional[customer_update_params.TaxConfiguration] | Omit = omit, + tax_id: Optional[CustomerTaxID] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Customer: """ This endpoint can be used to update the `payment_provider`, `payment_provider_id`, `name`, `email`, `email_delivery`, `tax_id`, - `auto_collection`, `metadata`, `shipping_address`, `billing_address`, and - `additional_emails` of an existing customer. Other fields on a customer are - currently immutable. + `auto_collection`, `metadata`, `shipping_address`, `billing_address`, + `additional_emails`, and `currency` of an existing customer. `currency` can only + be set if it has not already been set on the customer. Other fields on a + customer are currently immutable. Args: additional_emails: Additional email addresses for this customer. If populated, these email - addresses will be CC'd for customer communications. + addresses will be CC'd for customer communications. The total number of email + addresses (including the primary email) cannot exceed 50. auto_collection: Used to determine if invoices for this customer will automatically attempt to charge a saved payment method, if available. This parameter defaults to `True` when a payment provider is provided on customer creation. - currency: An ISO 4217 currency string used for the customer's invoices and balance. If not - set at creation time, will be set at subscription creation time. + auto_issuance: Used to determine if invoices for this customer will be automatically issued. If + true, invoices will be automatically issued. If false, invoices will require + manual approval.If `null` is specified, the customer's auto issuance setting + will be inherited from the account-level setting. + + currency: An ISO 4217 currency string used for the customer's invoices and balance. This + can only be set if the customer does not already have a currency configured. If + not set at creation or update time, it will be set at subscription creation + time. + + default_payment_method_id: The Orb ID of the payment method to set as this customer's default. Pass `null` + to clear the customer's default payment method. email: A valid customer email, to be used for invoicing and notifications. - external_customer_id: The external customer ID. This can only be set if empty and the customer has no - past or current subscriptions. + external_customer_id: The external customer ID. This can only be set if the customer has no existing + external customer ID. Since this action may change usage quantities for all + existing subscriptions, it is disallowed if the customer has issued invoices + with usage line items and subject to the same restrictions as backdated + subscription creation. + + hierarchy: The hierarchical relationships for this customer. 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 @@ -357,6 +514,9 @@ def update( name: The full name of the customer + payment_configuration: Payment configuration for the customer, applicable when using Orb Invoicing with + a supported payment provider such as Stripe. + payment_provider: This is used for creating charges or invoices in an external system via Orb. When not in test mode: @@ -373,86 +533,151 @@ def update( ### Supported Tax ID Countries and Types - | Country | Type | Description | - | -------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | - | Andorra | `ad_nrt` | Andorran NRT number | - | Australia | `au_abn` | Australian Business Number (AU ABN) | - | Australia | `au_arn` | Australian Taxation Office Reference Number | - | Austria | `eu_vat` | European VAT number | - | Belgium | `eu_vat` | European VAT number | - | Brazil | `br_cnpj` | Brazilian CNPJ number | - | Brazil | `br_cpf` | Brazilian CPF number | - | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | - | Bulgaria | `eu_vat` | European VAT number | - | Canada | `ca_bn` | Canadian BN | - | Canada | `ca_gst_hst` | Canadian GST/HST number | - | Canada | `ca_pst_bc` | Canadian PST number (British Columbia) | - | Canada | `ca_pst_mb` | Canadian PST number (Manitoba) | - | Canada | `ca_pst_sk` | Canadian PST number (Saskatchewan) | - | Canada | `ca_qst` | Canadian QST number (Québec) | - | Chile | `cl_tin` | Chilean TIN | - | Croatia | `eu_vat` | European VAT number | - | Cyprus | `eu_vat` | European VAT number | - | Czech Republic | `eu_vat` | European VAT number | - | Denmark | `eu_vat` | European VAT number | - | Egypt | `eg_tin` | Egyptian Tax Identification Number | - | Estonia | `eu_vat` | European VAT number | - | EU | `eu_oss_vat` | European One Stop Shop VAT number for non-Union scheme | - | Finland | `eu_vat` | European VAT number | - | France | `eu_vat` | European VAT number | - | Georgia | `ge_vat` | Georgian VAT | - | Germany | `eu_vat` | European VAT number | - | Greece | `eu_vat` | European VAT number | - | Hong Kong | `hk_br` | Hong Kong BR number | - | Hungary | `eu_vat` | European VAT number | - | Hungary | `hu_tin` | Hungary tax number (adószám) | - | Iceland | `is_vat` | Icelandic VAT | - | India | `in_gst` | Indian GST number | - | Indonesia | `id_npwp` | Indonesian NPWP number | - | Ireland | `eu_vat` | European VAT number | - | Israel | `il_vat` | Israel VAT | - | Italy | `eu_vat` | European VAT number | - | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | - | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | - | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | - | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | - | Latvia | `eu_vat` | European VAT number | - | Liechtenstein | `li_uid` | Liechtensteinian UID number | - | Lithuania | `eu_vat` | European VAT number | - | Luxembourg | `eu_vat` | European VAT number | - | Malaysia | `my_frp` | Malaysian FRP number | - | Malaysia | `my_itn` | Malaysian ITN | - | Malaysia | `my_sst` | Malaysian SST number | - | Malta | `eu_vat ` | European VAT number | - | Mexico | `mx_rfc` | Mexican RFC number | - | Netherlands | `eu_vat` | European VAT number | - | New Zealand | `nz_gst` | New Zealand GST number | - | Norway | `no_vat` | Norwegian VAT number | - | Philippines | `ph_tin ` | Philippines Tax Identification Number | - | Poland | `eu_vat` | European VAT number | - | Portugal | `eu_vat` | European VAT number | - | Romania | `eu_vat` | European VAT number | - | Russia | `ru_inn` | Russian INN | - | Russia | `ru_kpp` | Russian KPP | - | Saudi Arabia | `sg_gst` | Singaporean GST | - | Singapore | `sg_uen` | Singaporean UEN | - | Slovakia | `eu_vat` | European VAT number | - | Slovenia | `eu_vat` | European VAT number | - | Slovenia | `si_tin` | Slovenia tax number (davčna številka) | - | South Africa | `za_vat` | South African VAT number | - | South Korea | `kr_brn` | Korean BRN | - | Spain | `es_cif` | Spanish NIF number (previously Spanish CIF number) | - | Spain | `eu_vat` | European VAT number | - | Sweden | `eu_vat` | European VAT number | - | Switzerland | `ch_vat` | Switzerland VAT number | - | Taiwan | `tw_vat` | Taiwanese VAT | - | Thailand | `th_vat` | Thai VAT | - | Turkey | `tr_tin` | Turkish Tax Identification Number | - | Ukraine | `ua_vat` | Ukrainian VAT | - | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | - | United Kingdom | `eu_vat` | Northern Ireland VAT number | - | United Kingdom | `gb_vat` | United Kingdom VAT number | - | United States | `us_ein` | United States EIN | + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | extra_headers: Send extra headers @@ -467,23 +692,28 @@ def update( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return self._put( - f"/customers/{customer_id}", + path_template("/customers/{customer_id}", customer_id=customer_id), body=maybe_transform( { "accounting_sync_configuration": accounting_sync_configuration, "additional_emails": additional_emails, "auto_collection": auto_collection, + "auto_issuance": auto_issuance, "billing_address": billing_address, "currency": currency, + "default_payment_method_id": default_payment_method_id, "email": email, "email_delivery": email_delivery, "external_customer_id": external_customer_id, + "hierarchy": hierarchy, "metadata": metadata, "name": name, + "payment_configuration": payment_configuration, "payment_provider": payment_provider, "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, @@ -501,28 +731,27 @@ def update( def list( self, *, - created_at_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[Customer]: """This endpoint returns a list of all customers for an account. The list of customers is ordered starting from the most recently created customer. This endpoint follows Orb's - [standardized pagination format](../reference/pagination). + [standardized pagination format](/api-reference/pagination). - See [Customer](../guides/concepts#customer) for an overview of the customer - model. + See [Customer](/core-concepts##customer) for an overview of the customer model. Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -570,22 +799,22 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, 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 customer on subsequent GET requests while deletion is in process will reflect - its deletion with a `deleted: true` property. Once the customer deletion has - been fully processed, the customer will not be returned in the API. - - On successful processing, this returns an empty dictionary (`{}`) in the API. + its deletion. Args: extra_headers: Send extra headers @@ -602,7 +831,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/customers/{customer_id}", + path_template("/customers/{customer_id}", customer_id=customer_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -622,7 +851,7 @@ def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Customer: """This endpoint is used to fetch customer details given an identifier. @@ -630,8 +859,8 @@ def fetch( `Customer` is in the process of being deleted, only the properties `id` and `deleted: true` will be returned. - See the [Customer resource](../guides/core-concepts.mdx#customer) for a full - discussion of the Customer model. + See the [Customer resource](/core-concepts#customer) for a full discussion of + the Customer model. Args: extra_headers: Send extra headers @@ -645,7 +874,7 @@ def fetch( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return self._get( - f"/customers/{customer_id}", + path_template("/customers/{customer_id}", customer_id=customer_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -661,11 +890,11 @@ def fetch_by_external_id( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Customer: """ This endpoint is used to fetch customer details given an `external_customer_id` - (see [Customer ID Aliases](../guides/events-and-metrics/customer-aliases)). + (see [Customer ID Aliases](/events-and-metrics/customer-aliases)). Note that the resource and semantics of this endpoint exactly mirror [Get Customer](fetch-customer). @@ -684,64 +913,184 @@ def fetch_by_external_id( f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" ) return self._get( - f"/customers/external_customer_id/{external_customer_id}", + path_template( + "/customers/external_customer_id/{external_customer_id}", external_customer_id=external_customer_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=Customer, ) + def sync_payment_methods_from_gateway( + self, + customer_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> None: + """ + Sync Orb's payment methods for the customer with their gateway. + + This method can be called before taking an action that may cause the customer to + be charged, ensuring that the most up-to-date payment method is charged. + + **Note**: This functionality is currently only available for Stripe. + + Args: + 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 customer_id: + raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + path_template("/customers/{customer_id}/sync_payment_methods_from_gateway", customer_id=customer_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=NoneType, + ) + + def sync_payment_methods_from_gateway_by_external_customer_id( + self, + external_customer_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> None: + """ + Sync Orb's payment methods for the customer with their gateway. + + This method can be called before taking an action that may cause the customer to + be charged, ensuring that the most up-to-date payment method is charged. + + **Note**: This functionality is currently only available for Stripe. + + Args: + 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 external_customer_id: + raise ValueError( + f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" + ) + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + path_template( + "/customers/external_customer_id/{external_customer_id}/sync_payment_methods_from_gateway", + external_customer_id=external_customer_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=NoneType, + ) + def update_by_external_id( self, id: str, *, - accounting_sync_configuration: Optional[customer_update_by_external_id_params.AccountingSyncConfiguration] - | NotGiven = NOT_GIVEN, - additional_emails: Optional[List[str]] | NotGiven = NOT_GIVEN, - auto_collection: Optional[bool] | NotGiven = NOT_GIVEN, - billing_address: Optional[customer_update_by_external_id_params.BillingAddress] | NotGiven = NOT_GIVEN, - currency: Optional[str] | NotGiven = NOT_GIVEN, - email: Optional[str] | NotGiven = NOT_GIVEN, - email_delivery: Optional[bool] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - payment_provider: Optional[Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite"]] - | NotGiven = NOT_GIVEN, - payment_provider_id: Optional[str] | NotGiven = NOT_GIVEN, - 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_id: Optional[customer_update_by_external_id_params.TaxID] | NotGiven = NOT_GIVEN, + accounting_sync_configuration: Optional[NewAccountingSyncConfigurationParam] | Omit = omit, + additional_emails: Optional[SequenceNotStr[str]] | Omit = omit, + auto_collection: Optional[bool] | Omit = omit, + auto_issuance: Optional[bool] | Omit = omit, + billing_address: Optional[AddressInputParam] | Omit = omit, + currency: Optional[str] | Omit = omit, + default_payment_method_id: Optional[str] | Omit = omit, + email: Optional[str] | Omit = omit, + email_delivery: Optional[bool] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + hierarchy: Optional[CustomerHierarchyConfigParam] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + name: Optional[str] | Omit = omit, + payment_configuration: Optional[customer_update_by_external_id_params.PaymentConfiguration] | Omit = omit, + payment_provider: Optional[ + Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite", "adyen"] + ] + | Omit = omit, + payment_provider_id: Optional[str] | Omit = omit, + reporting_configuration: Optional[NewReportingConfigurationParam] | Omit = omit, + shipping_address: Optional[AddressInputParam] | Omit = omit, + tax_configuration: Optional[customer_update_by_external_id_params.TaxConfiguration] | Omit = omit, + tax_id: Optional[CustomerTaxID] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Customer: """ This endpoint is used to update customer details given an `external_customer_id` - (see [Customer ID Aliases](../guides/events-and-metrics/customer-aliases)). Note - that the resource and semantics of this endpoint exactly mirror + (see [Customer ID Aliases](/events-and-metrics/customer-aliases)). Note that the + resource and semantics of this endpoint exactly mirror [Update Customer](update-customer). Args: additional_emails: Additional email addresses for this customer. If populated, these email - addresses will be CC'd for customer communications. + addresses will be CC'd for customer communications. The total number of email + addresses (including the primary email) cannot exceed 50. auto_collection: Used to determine if invoices for this customer will automatically attempt to charge a saved payment method, if available. This parameter defaults to `True` when a payment provider is provided on customer creation. - currency: An ISO 4217 currency string used for the customer's invoices and balance. If not - set at creation time, will be set at subscription creation time. + auto_issuance: Used to determine if invoices for this customer will be automatically issued. If + true, invoices will be automatically issued. If false, invoices will require + manual approval.If `null` is specified, the customer's auto issuance setting + will be inherited from the account-level setting. + + currency: An ISO 4217 currency string used for the customer's invoices and balance. This + can only be set if the customer does not already have a currency configured. If + not set at creation or update time, it will be set at subscription creation + time. + + default_payment_method_id: The Orb ID of the payment method to set as this customer's default. Pass `null` + to clear the customer's default payment method. email: A valid customer email, to be used for invoicing and notifications. - external_customer_id: The external customer ID. This can only be set if empty and the customer has no - past or current subscriptions. + external_customer_id: The external customer ID. This can only be set if the customer has no existing + external customer ID. Since this action may change usage quantities for all + existing subscriptions, it is disallowed if the customer has issued invoices + with usage line items and subject to the same restrictions as backdated + subscription creation. + + hierarchy: The hierarchical relationships for this customer. 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 @@ -749,6 +1098,9 @@ def update_by_external_id( name: The full name of the customer + payment_configuration: Payment configuration for the customer, applicable when using Orb Invoicing with + a supported payment provider such as Stripe. + payment_provider: This is used for creating charges or invoices in an external system via Orb. When not in test mode: @@ -765,86 +1117,151 @@ def update_by_external_id( ### Supported Tax ID Countries and Types - | Country | Type | Description | - | -------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | - | Andorra | `ad_nrt` | Andorran NRT number | - | Australia | `au_abn` | Australian Business Number (AU ABN) | - | Australia | `au_arn` | Australian Taxation Office Reference Number | - | Austria | `eu_vat` | European VAT number | - | Belgium | `eu_vat` | European VAT number | - | Brazil | `br_cnpj` | Brazilian CNPJ number | - | Brazil | `br_cpf` | Brazilian CPF number | - | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | - | Bulgaria | `eu_vat` | European VAT number | - | Canada | `ca_bn` | Canadian BN | - | Canada | `ca_gst_hst` | Canadian GST/HST number | - | Canada | `ca_pst_bc` | Canadian PST number (British Columbia) | - | Canada | `ca_pst_mb` | Canadian PST number (Manitoba) | - | Canada | `ca_pst_sk` | Canadian PST number (Saskatchewan) | - | Canada | `ca_qst` | Canadian QST number (Québec) | - | Chile | `cl_tin` | Chilean TIN | - | Croatia | `eu_vat` | European VAT number | - | Cyprus | `eu_vat` | European VAT number | - | Czech Republic | `eu_vat` | European VAT number | - | Denmark | `eu_vat` | European VAT number | - | Egypt | `eg_tin` | Egyptian Tax Identification Number | - | Estonia | `eu_vat` | European VAT number | - | EU | `eu_oss_vat` | European One Stop Shop VAT number for non-Union scheme | - | Finland | `eu_vat` | European VAT number | - | France | `eu_vat` | European VAT number | - | Georgia | `ge_vat` | Georgian VAT | - | Germany | `eu_vat` | European VAT number | - | Greece | `eu_vat` | European VAT number | - | Hong Kong | `hk_br` | Hong Kong BR number | - | Hungary | `eu_vat` | European VAT number | - | Hungary | `hu_tin` | Hungary tax number (adószám) | - | Iceland | `is_vat` | Icelandic VAT | - | India | `in_gst` | Indian GST number | - | Indonesia | `id_npwp` | Indonesian NPWP number | - | Ireland | `eu_vat` | European VAT number | - | Israel | `il_vat` | Israel VAT | - | Italy | `eu_vat` | European VAT number | - | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | - | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | - | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | - | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | - | Latvia | `eu_vat` | European VAT number | - | Liechtenstein | `li_uid` | Liechtensteinian UID number | - | Lithuania | `eu_vat` | European VAT number | - | Luxembourg | `eu_vat` | European VAT number | - | Malaysia | `my_frp` | Malaysian FRP number | - | Malaysia | `my_itn` | Malaysian ITN | - | Malaysia | `my_sst` | Malaysian SST number | - | Malta | `eu_vat ` | European VAT number | - | Mexico | `mx_rfc` | Mexican RFC number | - | Netherlands | `eu_vat` | European VAT number | - | New Zealand | `nz_gst` | New Zealand GST number | - | Norway | `no_vat` | Norwegian VAT number | - | Philippines | `ph_tin ` | Philippines Tax Identification Number | - | Poland | `eu_vat` | European VAT number | - | Portugal | `eu_vat` | European VAT number | - | Romania | `eu_vat` | European VAT number | - | Russia | `ru_inn` | Russian INN | - | Russia | `ru_kpp` | Russian KPP | - | Saudi Arabia | `sg_gst` | Singaporean GST | - | Singapore | `sg_uen` | Singaporean UEN | - | Slovakia | `eu_vat` | European VAT number | - | Slovenia | `eu_vat` | European VAT number | - | Slovenia | `si_tin` | Slovenia tax number (davčna številka) | - | South Africa | `za_vat` | South African VAT number | - | South Korea | `kr_brn` | Korean BRN | - | Spain | `es_cif` | Spanish NIF number (previously Spanish CIF number) | - | Spain | `eu_vat` | European VAT number | - | Sweden | `eu_vat` | European VAT number | - | Switzerland | `ch_vat` | Switzerland VAT number | - | Taiwan | `tw_vat` | Taiwanese VAT | - | Thailand | `th_vat` | Thai VAT | - | Turkey | `tr_tin` | Turkish Tax Identification Number | - | Ukraine | `ua_vat` | Ukrainian VAT | - | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | - | United Kingdom | `eu_vat` | Northern Ireland VAT number | - | United Kingdom | `gb_vat` | United Kingdom VAT number | - | United States | `us_ein` | United States EIN | + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | extra_headers: Send extra headers @@ -859,23 +1276,28 @@ def update_by_external_id( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return self._put( - f"/customers/external_customer_id/{id}", + path_template("/customers/external_customer_id/{id}", id=id), body=maybe_transform( { "accounting_sync_configuration": accounting_sync_configuration, "additional_emails": additional_emails, "auto_collection": auto_collection, + "auto_issuance": auto_issuance, "billing_address": billing_address, "currency": currency, + "default_payment_method_id": default_payment_method_id, "email": email, "email_delivery": email_delivery, "external_customer_id": external_customer_id, + "hierarchy": hierarchy, "metadata": metadata, "name": name, + "payment_configuration": payment_configuration, "payment_provider": payment_provider, "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, @@ -892,28 +1314,87 @@ def update_by_external_id( class AsyncCustomers(AsyncAPIResource): + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + @cached_property def costs(self) -> AsyncCosts: - return AsyncCosts(self._client) + """ + A customer is a buyer of your products, and the other party to the billing relationship. - @cached_property - def usage(self) -> AsyncUsage: - return AsyncUsage(self._client) + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + return AsyncCosts(self._client) @cached_property def credits(self) -> AsyncCredits: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return AsyncCredits(self._client) @cached_property def balance_transactions(self) -> AsyncBalanceTransactions: + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ return AsyncBalanceTransactions(self._client) @cached_property def with_raw_response(self) -> AsyncCustomersWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -921,43 +1402,48 @@ async def create( *, email: str, name: str, - accounting_sync_configuration: Optional[customer_create_params.AccountingSyncConfiguration] - | NotGiven = NOT_GIVEN, - additional_emails: Optional[List[str]] | NotGiven = NOT_GIVEN, - auto_collection: Optional[bool] | NotGiven = NOT_GIVEN, - billing_address: Optional[customer_create_params.BillingAddress] | NotGiven = NOT_GIVEN, - currency: Optional[str] | NotGiven = NOT_GIVEN, - email_delivery: Optional[bool] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - payment_provider: Optional[Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite"]] - | NotGiven = NOT_GIVEN, - 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_id: Optional[customer_create_params.TaxID] | NotGiven = NOT_GIVEN, - timezone: Optional[str] | NotGiven = NOT_GIVEN, + accounting_sync_configuration: Optional[NewAccountingSyncConfigurationParam] | Omit = omit, + additional_emails: Optional[SequenceNotStr[str]] | Omit = omit, + auto_collection: Optional[bool] | Omit = omit, + auto_issuance: Optional[bool] | Omit = omit, + billing_address: Optional[AddressInputParam] | Omit = omit, + currency: Optional[str] | Omit = omit, + email_delivery: Optional[bool] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + hierarchy: Optional[CustomerHierarchyConfigParam] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + payment_configuration: Optional[customer_create_params.PaymentConfiguration] | Omit = omit, + payment_provider: Optional[ + Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite", "adyen"] + ] + | Omit = omit, + payment_provider_id: Optional[str] | Omit = omit, + reporting_configuration: Optional[NewReportingConfigurationParam] | Omit = omit, + shipping_address: Optional[AddressInputParam] | Omit = omit, + tax_configuration: Optional[customer_create_params.TaxConfiguration] | Omit = omit, + tax_id: Optional[CustomerTaxID] | Omit = omit, + timezone: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Customer: """ This operation is used to create an Orb customer, who is party to the core - billing relationship. See [Customer](../guides/concepts#customer) for an - overview of the customer resource. + billing relationship. See [Customer](/core-concepts##customer) for an overview + of the customer resource. This endpoint is critical in the following Orb functionality: - Automated charges can be configured by setting `payment_provider` and `payment_provider_id` to automatically issue invoices - - [Customer ID Aliases](../guides/events-and-metrics/customer-aliases) can be - configured by setting `external_customer_id` - - [Timezone localization](../guides/product-catalog/timezones.md) can be - configured on a per-customer basis by setting the `timezone` parameter + - [Customer ID Aliases](/events-and-metrics/customer-aliases) can be configured + by setting `external_customer_id` + - [Timezone localization](/essentials/timezones) can be configured on a + per-customer basis by setting the `timezone` parameter Args: email: A valid customer email, to be used for notifications. When Orb triggers payment @@ -967,12 +1453,18 @@ async def create( name: The full name of the customer additional_emails: Additional email addresses for this customer. If populated, these email - addresses will be CC'd for customer communications. + addresses will be CC'd for customer communications. The total number of email + addresses (including the primary email) cannot exceed 50. auto_collection: Used to determine if invoices for this customer will automatically attempt to charge a saved payment method, if available. This parameter defaults to `True` when a payment provider is provided on customer creation. + auto_issuance: Used to determine if invoices for this customer will be automatically issued. If + true, invoices will be automatically issued. If false, invoices will require + manual approval. If `null` is specified, the customer's auto issuance setting + will be inherited from the account-level setting. + currency: An ISO 4217 currency string used for the customer's invoices and balance. If not set at creation time, will be set at subscription creation time. @@ -980,10 +1472,15 @@ async def create( system as an alias for this Customer. Use this field to identify a customer by an existing identifier in your system. + hierarchy: The hierarchical relationships for this customer. + 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`. + payment_configuration: Payment configuration for the customer, applicable when using Orb Invoicing with + a supported payment provider such as Stripe. + payment_provider: This is used for creating charges or invoices in an external system via Orb. When not in test mode, the connection must first be configured in the Orb webapp. @@ -996,86 +1493,151 @@ async def create( ### Supported Tax ID Countries and Types - | Country | Type | Description | - | -------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | - | Andorra | `ad_nrt` | Andorran NRT number | - | Australia | `au_abn` | Australian Business Number (AU ABN) | - | Australia | `au_arn` | Australian Taxation Office Reference Number | - | Austria | `eu_vat` | European VAT number | - | Belgium | `eu_vat` | European VAT number | - | Brazil | `br_cnpj` | Brazilian CNPJ number | - | Brazil | `br_cpf` | Brazilian CPF number | - | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | - | Bulgaria | `eu_vat` | European VAT number | - | Canada | `ca_bn` | Canadian BN | - | Canada | `ca_gst_hst` | Canadian GST/HST number | - | Canada | `ca_pst_bc` | Canadian PST number (British Columbia) | - | Canada | `ca_pst_mb` | Canadian PST number (Manitoba) | - | Canada | `ca_pst_sk` | Canadian PST number (Saskatchewan) | - | Canada | `ca_qst` | Canadian QST number (Québec) | - | Chile | `cl_tin` | Chilean TIN | - | Croatia | `eu_vat` | European VAT number | - | Cyprus | `eu_vat` | European VAT number | - | Czech Republic | `eu_vat` | European VAT number | - | Denmark | `eu_vat` | European VAT number | - | Egypt | `eg_tin` | Egyptian Tax Identification Number | - | Estonia | `eu_vat` | European VAT number | - | EU | `eu_oss_vat` | European One Stop Shop VAT number for non-Union scheme | - | Finland | `eu_vat` | European VAT number | - | France | `eu_vat` | European VAT number | - | Georgia | `ge_vat` | Georgian VAT | - | Germany | `eu_vat` | European VAT number | - | Greece | `eu_vat` | European VAT number | - | Hong Kong | `hk_br` | Hong Kong BR number | - | Hungary | `eu_vat` | European VAT number | - | Hungary | `hu_tin` | Hungary tax number (adószám) | - | Iceland | `is_vat` | Icelandic VAT | - | India | `in_gst` | Indian GST number | - | Indonesia | `id_npwp` | Indonesian NPWP number | - | Ireland | `eu_vat` | European VAT number | - | Israel | `il_vat` | Israel VAT | - | Italy | `eu_vat` | European VAT number | - | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | - | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | - | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | - | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | - | Latvia | `eu_vat` | European VAT number | - | Liechtenstein | `li_uid` | Liechtensteinian UID number | - | Lithuania | `eu_vat` | European VAT number | - | Luxembourg | `eu_vat` | European VAT number | - | Malaysia | `my_frp` | Malaysian FRP number | - | Malaysia | `my_itn` | Malaysian ITN | - | Malaysia | `my_sst` | Malaysian SST number | - | Malta | `eu_vat ` | European VAT number | - | Mexico | `mx_rfc` | Mexican RFC number | - | Netherlands | `eu_vat` | European VAT number | - | New Zealand | `nz_gst` | New Zealand GST number | - | Norway | `no_vat` | Norwegian VAT number | - | Philippines | `ph_tin ` | Philippines Tax Identification Number | - | Poland | `eu_vat` | European VAT number | - | Portugal | `eu_vat` | European VAT number | - | Romania | `eu_vat` | European VAT number | - | Russia | `ru_inn` | Russian INN | - | Russia | `ru_kpp` | Russian KPP | - | Saudi Arabia | `sg_gst` | Singaporean GST | - | Singapore | `sg_uen` | Singaporean UEN | - | Slovakia | `eu_vat` | European VAT number | - | Slovenia | `eu_vat` | European VAT number | - | Slovenia | `si_tin` | Slovenia tax number (davčna številka) | - | South Africa | `za_vat` | South African VAT number | - | South Korea | `kr_brn` | Korean BRN | - | Spain | `es_cif` | Spanish NIF number (previously Spanish CIF number) | - | Spain | `eu_vat` | European VAT number | - | Sweden | `eu_vat` | European VAT number | - | Switzerland | `ch_vat` | Switzerland VAT number | - | Taiwan | `tw_vat` | Taiwanese VAT | - | Thailand | `th_vat` | Thai VAT | - | Turkey | `tr_tin` | Turkish Tax Identification Number | - | Ukraine | `ua_vat` | Ukrainian VAT | - | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | - | United Kingdom | `eu_vat` | Northern Ireland VAT number | - | United Kingdom | `gb_vat` | United Kingdom VAT number | - | United States | `us_ein` | United States EIN | + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | timezone: A timezone identifier from the IANA timezone database, such as `"America/Los_Angeles"`. This defaults to your account's timezone if not set. @@ -1100,15 +1662,19 @@ async def create( "accounting_sync_configuration": accounting_sync_configuration, "additional_emails": additional_emails, "auto_collection": auto_collection, + "auto_issuance": auto_issuance, "billing_address": billing_address, "currency": currency, "email_delivery": email_delivery, "external_customer_id": external_customer_id, + "hierarchy": hierarchy, "metadata": metadata, + "payment_configuration": payment_configuration, "payment_provider": payment_provider, "payment_provider_id": payment_provider_id, "reporting_configuration": reporting_configuration, "shipping_address": shipping_address, + "tax_configuration": tax_configuration, "tax_id": tax_id, "timezone": timezone, }, @@ -1128,53 +1694,76 @@ async def update( self, customer_id: str, *, - accounting_sync_configuration: Optional[customer_update_params.AccountingSyncConfiguration] - | NotGiven = NOT_GIVEN, - additional_emails: Optional[List[str]] | NotGiven = NOT_GIVEN, - auto_collection: Optional[bool] | NotGiven = NOT_GIVEN, - billing_address: Optional[customer_update_params.BillingAddress] | NotGiven = NOT_GIVEN, - currency: Optional[str] | NotGiven = NOT_GIVEN, - email: Optional[str] | NotGiven = NOT_GIVEN, - email_delivery: Optional[bool] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - payment_provider: Optional[Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite"]] - | NotGiven = NOT_GIVEN, - 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_id: Optional[customer_update_params.TaxID] | NotGiven = NOT_GIVEN, + accounting_sync_configuration: Optional[NewAccountingSyncConfigurationParam] | Omit = omit, + additional_emails: Optional[SequenceNotStr[str]] | Omit = omit, + auto_collection: Optional[bool] | Omit = omit, + auto_issuance: Optional[bool] | Omit = omit, + billing_address: Optional[AddressInputParam] | Omit = omit, + currency: Optional[str] | Omit = omit, + default_payment_method_id: Optional[str] | Omit = omit, + email: Optional[str] | Omit = omit, + email_delivery: Optional[bool] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + hierarchy: Optional[CustomerHierarchyConfigParam] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + name: Optional[str] | Omit = omit, + payment_configuration: Optional[customer_update_params.PaymentConfiguration] | Omit = omit, + payment_provider: Optional[ + Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite", "adyen"] + ] + | Omit = omit, + payment_provider_id: Optional[str] | Omit = omit, + reporting_configuration: Optional[NewReportingConfigurationParam] | Omit = omit, + shipping_address: Optional[AddressInputParam] | Omit = omit, + tax_configuration: Optional[customer_update_params.TaxConfiguration] | Omit = omit, + tax_id: Optional[CustomerTaxID] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Customer: """ This endpoint can be used to update the `payment_provider`, `payment_provider_id`, `name`, `email`, `email_delivery`, `tax_id`, - `auto_collection`, `metadata`, `shipping_address`, `billing_address`, and - `additional_emails` of an existing customer. Other fields on a customer are - currently immutable. + `auto_collection`, `metadata`, `shipping_address`, `billing_address`, + `additional_emails`, and `currency` of an existing customer. `currency` can only + be set if it has not already been set on the customer. Other fields on a + customer are currently immutable. Args: additional_emails: Additional email addresses for this customer. If populated, these email - addresses will be CC'd for customer communications. + addresses will be CC'd for customer communications. The total number of email + addresses (including the primary email) cannot exceed 50. auto_collection: Used to determine if invoices for this customer will automatically attempt to charge a saved payment method, if available. This parameter defaults to `True` when a payment provider is provided on customer creation. - currency: An ISO 4217 currency string used for the customer's invoices and balance. If not - set at creation time, will be set at subscription creation time. + auto_issuance: Used to determine if invoices for this customer will be automatically issued. If + true, invoices will be automatically issued. If false, invoices will require + manual approval.If `null` is specified, the customer's auto issuance setting + will be inherited from the account-level setting. + + currency: An ISO 4217 currency string used for the customer's invoices and balance. This + can only be set if the customer does not already have a currency configured. If + not set at creation or update time, it will be set at subscription creation + time. + + default_payment_method_id: The Orb ID of the payment method to set as this customer's default. Pass `null` + to clear the customer's default payment method. email: A valid customer email, to be used for invoicing and notifications. - external_customer_id: The external customer ID. This can only be set if empty and the customer has no - past or current subscriptions. + external_customer_id: The external customer ID. This can only be set if the customer has no existing + external customer ID. Since this action may change usage quantities for all + existing subscriptions, it is disallowed if the customer has issued invoices + with usage line items and subject to the same restrictions as backdated + subscription creation. + + hierarchy: The hierarchical relationships for this customer. 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 @@ -1182,6 +1771,9 @@ async def update( name: The full name of the customer + payment_configuration: Payment configuration for the customer, applicable when using Orb Invoicing with + a supported payment provider such as Stripe. + payment_provider: This is used for creating charges or invoices in an external system via Orb. When not in test mode: @@ -1198,86 +1790,151 @@ async def update( ### Supported Tax ID Countries and Types - | Country | Type | Description | - | -------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | - | Andorra | `ad_nrt` | Andorran NRT number | - | Australia | `au_abn` | Australian Business Number (AU ABN) | - | Australia | `au_arn` | Australian Taxation Office Reference Number | - | Austria | `eu_vat` | European VAT number | - | Belgium | `eu_vat` | European VAT number | - | Brazil | `br_cnpj` | Brazilian CNPJ number | - | Brazil | `br_cpf` | Brazilian CPF number | - | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | - | Bulgaria | `eu_vat` | European VAT number | - | Canada | `ca_bn` | Canadian BN | - | Canada | `ca_gst_hst` | Canadian GST/HST number | - | Canada | `ca_pst_bc` | Canadian PST number (British Columbia) | - | Canada | `ca_pst_mb` | Canadian PST number (Manitoba) | - | Canada | `ca_pst_sk` | Canadian PST number (Saskatchewan) | - | Canada | `ca_qst` | Canadian QST number (Québec) | - | Chile | `cl_tin` | Chilean TIN | - | Croatia | `eu_vat` | European VAT number | - | Cyprus | `eu_vat` | European VAT number | - | Czech Republic | `eu_vat` | European VAT number | - | Denmark | `eu_vat` | European VAT number | - | Egypt | `eg_tin` | Egyptian Tax Identification Number | - | Estonia | `eu_vat` | European VAT number | - | EU | `eu_oss_vat` | European One Stop Shop VAT number for non-Union scheme | - | Finland | `eu_vat` | European VAT number | - | France | `eu_vat` | European VAT number | - | Georgia | `ge_vat` | Georgian VAT | - | Germany | `eu_vat` | European VAT number | - | Greece | `eu_vat` | European VAT number | - | Hong Kong | `hk_br` | Hong Kong BR number | - | Hungary | `eu_vat` | European VAT number | - | Hungary | `hu_tin` | Hungary tax number (adószám) | - | Iceland | `is_vat` | Icelandic VAT | - | India | `in_gst` | Indian GST number | - | Indonesia | `id_npwp` | Indonesian NPWP number | - | Ireland | `eu_vat` | European VAT number | - | Israel | `il_vat` | Israel VAT | - | Italy | `eu_vat` | European VAT number | - | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | - | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | - | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | - | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | - | Latvia | `eu_vat` | European VAT number | - | Liechtenstein | `li_uid` | Liechtensteinian UID number | - | Lithuania | `eu_vat` | European VAT number | - | Luxembourg | `eu_vat` | European VAT number | - | Malaysia | `my_frp` | Malaysian FRP number | - | Malaysia | `my_itn` | Malaysian ITN | - | Malaysia | `my_sst` | Malaysian SST number | - | Malta | `eu_vat ` | European VAT number | - | Mexico | `mx_rfc` | Mexican RFC number | - | Netherlands | `eu_vat` | European VAT number | - | New Zealand | `nz_gst` | New Zealand GST number | - | Norway | `no_vat` | Norwegian VAT number | - | Philippines | `ph_tin ` | Philippines Tax Identification Number | - | Poland | `eu_vat` | European VAT number | - | Portugal | `eu_vat` | European VAT number | - | Romania | `eu_vat` | European VAT number | - | Russia | `ru_inn` | Russian INN | - | Russia | `ru_kpp` | Russian KPP | - | Saudi Arabia | `sg_gst` | Singaporean GST | - | Singapore | `sg_uen` | Singaporean UEN | - | Slovakia | `eu_vat` | European VAT number | - | Slovenia | `eu_vat` | European VAT number | - | Slovenia | `si_tin` | Slovenia tax number (davčna številka) | - | South Africa | `za_vat` | South African VAT number | - | South Korea | `kr_brn` | Korean BRN | - | Spain | `es_cif` | Spanish NIF number (previously Spanish CIF number) | - | Spain | `eu_vat` | European VAT number | - | Sweden | `eu_vat` | European VAT number | - | Switzerland | `ch_vat` | Switzerland VAT number | - | Taiwan | `tw_vat` | Taiwanese VAT | - | Thailand | `th_vat` | Thai VAT | - | Turkey | `tr_tin` | Turkish Tax Identification Number | - | Ukraine | `ua_vat` | Ukrainian VAT | - | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | - | United Kingdom | `eu_vat` | Northern Ireland VAT number | - | United Kingdom | `gb_vat` | United Kingdom VAT number | - | United States | `us_ein` | United States EIN | + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | extra_headers: Send extra headers @@ -1292,23 +1949,28 @@ async def update( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return await self._put( - f"/customers/{customer_id}", + path_template("/customers/{customer_id}", customer_id=customer_id), body=await async_maybe_transform( { "accounting_sync_configuration": accounting_sync_configuration, "additional_emails": additional_emails, "auto_collection": auto_collection, + "auto_issuance": auto_issuance, "billing_address": billing_address, "currency": currency, + "default_payment_method_id": default_payment_method_id, "email": email, "email_delivery": email_delivery, "external_customer_id": external_customer_id, + "hierarchy": hierarchy, "metadata": metadata, "name": name, + "payment_configuration": payment_configuration, "payment_provider": payment_provider, "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, @@ -1326,28 +1988,27 @@ async def update( def list( self, *, - created_at_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Customer, AsyncPage[Customer]]: """This endpoint returns a list of all customers for an account. The list of customers is ordered starting from the most recently created customer. This endpoint follows Orb's - [standardized pagination format](../reference/pagination). + [standardized pagination format](/api-reference/pagination). - See [Customer](../guides/concepts#customer) for an overview of the customer - model. + See [Customer](/core-concepts##customer) for an overview of the customer model. Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -1395,22 +2056,22 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, 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 customer on subsequent GET requests while deletion is in process will reflect - its deletion with a `deleted: true` property. Once the customer deletion has - been fully processed, the customer will not be returned in the API. - - On successful processing, this returns an empty dictionary (`{}`) in the API. + its deletion. Args: extra_headers: Send extra headers @@ -1427,7 +2088,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/customers/{customer_id}", + path_template("/customers/{customer_id}", customer_id=customer_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -1447,7 +2108,7 @@ async def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Customer: """This endpoint is used to fetch customer details given an identifier. @@ -1455,8 +2116,8 @@ async def fetch( `Customer` is in the process of being deleted, only the properties `id` and `deleted: true` will be returned. - See the [Customer resource](../guides/core-concepts.mdx#customer) for a full - discussion of the Customer model. + See the [Customer resource](/core-concepts#customer) for a full discussion of + the Customer model. Args: extra_headers: Send extra headers @@ -1470,7 +2131,7 @@ async def fetch( if not customer_id: raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") return await self._get( - f"/customers/{customer_id}", + path_template("/customers/{customer_id}", customer_id=customer_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1486,11 +2147,11 @@ async def fetch_by_external_id( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Customer: """ This endpoint is used to fetch customer details given an `external_customer_id` - (see [Customer ID Aliases](../guides/events-and-metrics/customer-aliases)). + (see [Customer ID Aliases](/events-and-metrics/customer-aliases)). Note that the resource and semantics of this endpoint exactly mirror [Get Customer](fetch-customer). @@ -1509,64 +2170,184 @@ async def fetch_by_external_id( f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" ) return await self._get( - f"/customers/external_customer_id/{external_customer_id}", + path_template( + "/customers/external_customer_id/{external_customer_id}", external_customer_id=external_customer_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=Customer, ) + async def sync_payment_methods_from_gateway( + self, + customer_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> None: + """ + Sync Orb's payment methods for the customer with their gateway. + + This method can be called before taking an action that may cause the customer to + be charged, ensuring that the most up-to-date payment method is charged. + + **Note**: This functionality is currently only available for Stripe. + + Args: + 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 customer_id: + raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + path_template("/customers/{customer_id}/sync_payment_methods_from_gateway", customer_id=customer_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=NoneType, + ) + + async def sync_payment_methods_from_gateway_by_external_customer_id( + self, + external_customer_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> None: + """ + Sync Orb's payment methods for the customer with their gateway. + + This method can be called before taking an action that may cause the customer to + be charged, ensuring that the most up-to-date payment method is charged. + + **Note**: This functionality is currently only available for Stripe. + + Args: + 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 external_customer_id: + raise ValueError( + f"Expected a non-empty value for `external_customer_id` but received {external_customer_id!r}" + ) + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + path_template( + "/customers/external_customer_id/{external_customer_id}/sync_payment_methods_from_gateway", + external_customer_id=external_customer_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=NoneType, + ) + async def update_by_external_id( self, id: str, *, - accounting_sync_configuration: Optional[customer_update_by_external_id_params.AccountingSyncConfiguration] - | NotGiven = NOT_GIVEN, - additional_emails: Optional[List[str]] | NotGiven = NOT_GIVEN, - auto_collection: Optional[bool] | NotGiven = NOT_GIVEN, - billing_address: Optional[customer_update_by_external_id_params.BillingAddress] | NotGiven = NOT_GIVEN, - currency: Optional[str] | NotGiven = NOT_GIVEN, - email: Optional[str] | NotGiven = NOT_GIVEN, - email_delivery: Optional[bool] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - payment_provider: Optional[Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite"]] - | NotGiven = NOT_GIVEN, - payment_provider_id: Optional[str] | NotGiven = NOT_GIVEN, - 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_id: Optional[customer_update_by_external_id_params.TaxID] | NotGiven = NOT_GIVEN, + accounting_sync_configuration: Optional[NewAccountingSyncConfigurationParam] | Omit = omit, + additional_emails: Optional[SequenceNotStr[str]] | Omit = omit, + auto_collection: Optional[bool] | Omit = omit, + auto_issuance: Optional[bool] | Omit = omit, + billing_address: Optional[AddressInputParam] | Omit = omit, + currency: Optional[str] | Omit = omit, + default_payment_method_id: Optional[str] | Omit = omit, + email: Optional[str] | Omit = omit, + email_delivery: Optional[bool] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + hierarchy: Optional[CustomerHierarchyConfigParam] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + name: Optional[str] | Omit = omit, + payment_configuration: Optional[customer_update_by_external_id_params.PaymentConfiguration] | Omit = omit, + payment_provider: Optional[ + Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite", "adyen"] + ] + | Omit = omit, + payment_provider_id: Optional[str] | Omit = omit, + reporting_configuration: Optional[NewReportingConfigurationParam] | Omit = omit, + shipping_address: Optional[AddressInputParam] | Omit = omit, + tax_configuration: Optional[customer_update_by_external_id_params.TaxConfiguration] | Omit = omit, + tax_id: Optional[CustomerTaxID] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Customer: """ This endpoint is used to update customer details given an `external_customer_id` - (see [Customer ID Aliases](../guides/events-and-metrics/customer-aliases)). Note - that the resource and semantics of this endpoint exactly mirror + (see [Customer ID Aliases](/events-and-metrics/customer-aliases)). Note that the + resource and semantics of this endpoint exactly mirror [Update Customer](update-customer). Args: additional_emails: Additional email addresses for this customer. If populated, these email - addresses will be CC'd for customer communications. + addresses will be CC'd for customer communications. The total number of email + addresses (including the primary email) cannot exceed 50. auto_collection: Used to determine if invoices for this customer will automatically attempt to charge a saved payment method, if available. This parameter defaults to `True` when a payment provider is provided on customer creation. - currency: An ISO 4217 currency string used for the customer's invoices and balance. If not - set at creation time, will be set at subscription creation time. + auto_issuance: Used to determine if invoices for this customer will be automatically issued. If + true, invoices will be automatically issued. If false, invoices will require + manual approval.If `null` is specified, the customer's auto issuance setting + will be inherited from the account-level setting. + + currency: An ISO 4217 currency string used for the customer's invoices and balance. This + can only be set if the customer does not already have a currency configured. If + not set at creation or update time, it will be set at subscription creation + time. + + default_payment_method_id: The Orb ID of the payment method to set as this customer's default. Pass `null` + to clear the customer's default payment method. email: A valid customer email, to be used for invoicing and notifications. - external_customer_id: The external customer ID. This can only be set if empty and the customer has no - past or current subscriptions. + external_customer_id: The external customer ID. This can only be set if the customer has no existing + external customer ID. Since this action may change usage quantities for all + existing subscriptions, it is disallowed if the customer has issued invoices + with usage line items and subject to the same restrictions as backdated + subscription creation. + + hierarchy: The hierarchical relationships for this customer. 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 @@ -1574,6 +2355,9 @@ async def update_by_external_id( name: The full name of the customer + payment_configuration: Payment configuration for the customer, applicable when using Orb Invoicing with + a supported payment provider such as Stripe. + payment_provider: This is used for creating charges or invoices in an external system via Orb. When not in test mode: @@ -1590,86 +2374,151 @@ async def update_by_external_id( ### Supported Tax ID Countries and Types - | Country | Type | Description | - | -------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | - | Andorra | `ad_nrt` | Andorran NRT number | - | Australia | `au_abn` | Australian Business Number (AU ABN) | - | Australia | `au_arn` | Australian Taxation Office Reference Number | - | Austria | `eu_vat` | European VAT number | - | Belgium | `eu_vat` | European VAT number | - | Brazil | `br_cnpj` | Brazilian CNPJ number | - | Brazil | `br_cpf` | Brazilian CPF number | - | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | - | Bulgaria | `eu_vat` | European VAT number | - | Canada | `ca_bn` | Canadian BN | - | Canada | `ca_gst_hst` | Canadian GST/HST number | - | Canada | `ca_pst_bc` | Canadian PST number (British Columbia) | - | Canada | `ca_pst_mb` | Canadian PST number (Manitoba) | - | Canada | `ca_pst_sk` | Canadian PST number (Saskatchewan) | - | Canada | `ca_qst` | Canadian QST number (Québec) | - | Chile | `cl_tin` | Chilean TIN | - | Croatia | `eu_vat` | European VAT number | - | Cyprus | `eu_vat` | European VAT number | - | Czech Republic | `eu_vat` | European VAT number | - | Denmark | `eu_vat` | European VAT number | - | Egypt | `eg_tin` | Egyptian Tax Identification Number | - | Estonia | `eu_vat` | European VAT number | - | EU | `eu_oss_vat` | European One Stop Shop VAT number for non-Union scheme | - | Finland | `eu_vat` | European VAT number | - | France | `eu_vat` | European VAT number | - | Georgia | `ge_vat` | Georgian VAT | - | Germany | `eu_vat` | European VAT number | - | Greece | `eu_vat` | European VAT number | - | Hong Kong | `hk_br` | Hong Kong BR number | - | Hungary | `eu_vat` | European VAT number | - | Hungary | `hu_tin` | Hungary tax number (adószám) | - | Iceland | `is_vat` | Icelandic VAT | - | India | `in_gst` | Indian GST number | - | Indonesia | `id_npwp` | Indonesian NPWP number | - | Ireland | `eu_vat` | European VAT number | - | Israel | `il_vat` | Israel VAT | - | Italy | `eu_vat` | European VAT number | - | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | - | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | - | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | - | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | - | Latvia | `eu_vat` | European VAT number | - | Liechtenstein | `li_uid` | Liechtensteinian UID number | - | Lithuania | `eu_vat` | European VAT number | - | Luxembourg | `eu_vat` | European VAT number | - | Malaysia | `my_frp` | Malaysian FRP number | - | Malaysia | `my_itn` | Malaysian ITN | - | Malaysia | `my_sst` | Malaysian SST number | - | Malta | `eu_vat ` | European VAT number | - | Mexico | `mx_rfc` | Mexican RFC number | - | Netherlands | `eu_vat` | European VAT number | - | New Zealand | `nz_gst` | New Zealand GST number | - | Norway | `no_vat` | Norwegian VAT number | - | Philippines | `ph_tin ` | Philippines Tax Identification Number | - | Poland | `eu_vat` | European VAT number | - | Portugal | `eu_vat` | European VAT number | - | Romania | `eu_vat` | European VAT number | - | Russia | `ru_inn` | Russian INN | - | Russia | `ru_kpp` | Russian KPP | - | Saudi Arabia | `sg_gst` | Singaporean GST | - | Singapore | `sg_uen` | Singaporean UEN | - | Slovakia | `eu_vat` | European VAT number | - | Slovenia | `eu_vat` | European VAT number | - | Slovenia | `si_tin` | Slovenia tax number (davčna številka) | - | South Africa | `za_vat` | South African VAT number | - | South Korea | `kr_brn` | Korean BRN | - | Spain | `es_cif` | Spanish NIF number (previously Spanish CIF number) | - | Spain | `eu_vat` | European VAT number | - | Sweden | `eu_vat` | European VAT number | - | Switzerland | `ch_vat` | Switzerland VAT number | - | Taiwan | `tw_vat` | Taiwanese VAT | - | Thailand | `th_vat` | Thai VAT | - | Turkey | `tr_tin` | Turkish Tax Identification Number | - | Ukraine | `ua_vat` | Ukrainian VAT | - | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | - | United Kingdom | `eu_vat` | Northern Ireland VAT number | - | United Kingdom | `gb_vat` | United Kingdom VAT number | - | United States | `us_ein` | United States EIN | + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | extra_headers: Send extra headers @@ -1684,23 +2533,28 @@ async def update_by_external_id( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return await self._put( - f"/customers/external_customer_id/{id}", + path_template("/customers/external_customer_id/{id}", id=id), body=await async_maybe_transform( { "accounting_sync_configuration": accounting_sync_configuration, "additional_emails": additional_emails, "auto_collection": auto_collection, + "auto_issuance": auto_issuance, "billing_address": billing_address, "currency": currency, + "default_payment_method_id": default_payment_method_id, "email": email, "email_delivery": email_delivery, "external_customer_id": external_customer_id, + "hierarchy": hierarchy, "metadata": metadata, "name": name, + "payment_configuration": payment_configuration, "payment_provider": payment_provider, "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, @@ -1738,24 +2592,61 @@ def __init__(self, customers: Customers) -> None: self.fetch_by_external_id = _legacy_response.to_raw_response_wrapper( customers.fetch_by_external_id, ) + self.sync_payment_methods_from_gateway = _legacy_response.to_raw_response_wrapper( + customers.sync_payment_methods_from_gateway, + ) + self.sync_payment_methods_from_gateway_by_external_customer_id = _legacy_response.to_raw_response_wrapper( + customers.sync_payment_methods_from_gateway_by_external_customer_id, + ) self.update_by_external_id = _legacy_response.to_raw_response_wrapper( customers.update_by_external_id, ) @cached_property def costs(self) -> CostsWithRawResponse: - return CostsWithRawResponse(self._customers.costs) + """ + A customer is a buyer of your products, and the other party to the billing relationship. - @cached_property - def usage(self) -> UsageWithRawResponse: - return UsageWithRawResponse(self._customers.usage) + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + return CostsWithRawResponse(self._customers.costs) @cached_property def credits(self) -> CreditsWithRawResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return CreditsWithRawResponse(self._customers.credits) @cached_property def balance_transactions(self) -> BalanceTransactionsWithRawResponse: + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ return BalanceTransactionsWithRawResponse(self._customers.balance_transactions) @@ -1781,24 +2672,61 @@ def __init__(self, customers: AsyncCustomers) -> None: self.fetch_by_external_id = _legacy_response.async_to_raw_response_wrapper( customers.fetch_by_external_id, ) + self.sync_payment_methods_from_gateway = _legacy_response.async_to_raw_response_wrapper( + customers.sync_payment_methods_from_gateway, + ) + self.sync_payment_methods_from_gateway_by_external_customer_id = _legacy_response.async_to_raw_response_wrapper( + customers.sync_payment_methods_from_gateway_by_external_customer_id, + ) self.update_by_external_id = _legacy_response.async_to_raw_response_wrapper( customers.update_by_external_id, ) @cached_property def costs(self) -> AsyncCostsWithRawResponse: - return AsyncCostsWithRawResponse(self._customers.costs) + """ + A customer is a buyer of your products, and the other party to the billing relationship. - @cached_property - def usage(self) -> AsyncUsageWithRawResponse: - return AsyncUsageWithRawResponse(self._customers.usage) + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + return AsyncCostsWithRawResponse(self._customers.costs) @cached_property def credits(self) -> AsyncCreditsWithRawResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return AsyncCreditsWithRawResponse(self._customers.credits) @cached_property def balance_transactions(self) -> AsyncBalanceTransactionsWithRawResponse: + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ return AsyncBalanceTransactionsWithRawResponse(self._customers.balance_transactions) @@ -1824,24 +2752,61 @@ def __init__(self, customers: Customers) -> None: self.fetch_by_external_id = to_streamed_response_wrapper( customers.fetch_by_external_id, ) + self.sync_payment_methods_from_gateway = to_streamed_response_wrapper( + customers.sync_payment_methods_from_gateway, + ) + self.sync_payment_methods_from_gateway_by_external_customer_id = to_streamed_response_wrapper( + customers.sync_payment_methods_from_gateway_by_external_customer_id, + ) self.update_by_external_id = to_streamed_response_wrapper( customers.update_by_external_id, ) @cached_property def costs(self) -> CostsWithStreamingResponse: - return CostsWithStreamingResponse(self._customers.costs) + """ + A customer is a buyer of your products, and the other party to the billing relationship. - @cached_property - def usage(self) -> UsageWithStreamingResponse: - return UsageWithStreamingResponse(self._customers.usage) + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + return CostsWithStreamingResponse(self._customers.costs) @cached_property def credits(self) -> CreditsWithStreamingResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return CreditsWithStreamingResponse(self._customers.credits) @cached_property def balance_transactions(self) -> BalanceTransactionsWithStreamingResponse: + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ return BalanceTransactionsWithStreamingResponse(self._customers.balance_transactions) @@ -1867,22 +2832,59 @@ def __init__(self, customers: AsyncCustomers) -> None: self.fetch_by_external_id = async_to_streamed_response_wrapper( customers.fetch_by_external_id, ) + self.sync_payment_methods_from_gateway = async_to_streamed_response_wrapper( + customers.sync_payment_methods_from_gateway, + ) + self.sync_payment_methods_from_gateway_by_external_customer_id = async_to_streamed_response_wrapper( + customers.sync_payment_methods_from_gateway_by_external_customer_id, + ) self.update_by_external_id = async_to_streamed_response_wrapper( customers.update_by_external_id, ) @cached_property def costs(self) -> AsyncCostsWithStreamingResponse: - return AsyncCostsWithStreamingResponse(self._customers.costs) + """ + A customer is a buyer of your products, and the other party to the billing relationship. - @cached_property - def usage(self) -> AsyncUsageWithStreamingResponse: - return AsyncUsageWithStreamingResponse(self._customers.usage) + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + return AsyncCostsWithStreamingResponse(self._customers.costs) @cached_property def credits(self) -> AsyncCreditsWithStreamingResponse: + """ + The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid credits within Orb. + """ return AsyncCreditsWithStreamingResponse(self._customers.credits) @cached_property def balance_transactions(self) -> AsyncBalanceTransactionsWithStreamingResponse: + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ return AsyncBalanceTransactionsWithStreamingResponse(self._customers.balance_transactions) diff --git a/src/orb/resources/customers/usage.py b/src/orb/resources/customers/usage.py deleted file mode 100644 index de3aa59d..00000000 --- a/src/orb/resources/customers/usage.py +++ /dev/null @@ -1,711 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, 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.customers import ( - UsageUpdateResponse, - UsageUpdateByExternalIDResponse, - usage_update_params, - usage_update_by_external_id_params, -) - -__all__ = ["Usage", "AsyncUsage"] - - -class Usage(SyncAPIResource): - @cached_property - def with_raw_response(self) -> UsageWithRawResponse: - return UsageWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> UsageWithStreamingResponse: - return UsageWithStreamingResponse(self) - - def update( - self, - id: Optional[str], - *, - events: Iterable[usage_update_params.Event], - timeframe_end: Union[str, datetime] | NotGiven = NOT_GIVEN, - timeframe_start: 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, - idempotency_key: str | None = None, - ) -> UsageUpdateResponse: - """ - This endpoint is used to amend usage within a timeframe for a customer that has - an active subscription. - - This endpoint will mark _all_ existing events within - `[timeframe_start, timeframe_end)` as _ignored_ for billing purposes, and Orb - will only use the _new_ events passed in the body of this request as the source - of truth for that timeframe moving forwards. Note that a given time period can - be amended any number of times, so events can be overwritten in subsequent calls - to th is endpoint. - - This is a powerful and audit-safe mechanism to retroactively change usage data - in cases where you need to: - - - decrease historical usage consumption because of degraded service availability - in your systems - - account for gaps from your usage reporting mechanism - - make point-in-time fixes for specific event records, while retaining the - original time of usage and associated metadata. This amendment API is designed - with two explicit goals: - - 1. Amendments are **always audit-safe**. The amendment process will still retain - original events in the timeframe, though they will be ignored for billing - calculations. For auditing a nd data fidelity purposes, Orb never overwrites - or permanently deletes ingested usage data. - 2. Amendments always preserve data **consistency**. In other words, either an - amendment is fully processed by the system (and the new events for the - timeframe are honored rather than the existing ones) or the amendment request - fails. To maintain this important property, Orb prevents _partial event - ingestion_ on this endpoint. - - ## Response semantics - - - Either all events are ingested successfully, or all fail to ingest (returning - a `4xx` or `5xx` response code). - - Any event that fails schema validation will lead to a `4xx` response. In this - case, to maintain data consistency, Orb will not ingest any events and will - also not deprecate existing events in the time period. - - You can assume that the amendment is successful on receipt of a `2xx` - response.While a successful response from this endpoint indicates that the new - events have been ingested, updating usage totals happens asynchronously and - may be delayed by a few minutes. - - As emphasized above, Orb will never show an inconsistent state (e.g. in invoice - previews or dashboards); either it will show the existing state (before the - amendment) or the new state (with new events in the requested timeframe). - - ## Sample request body - - ```json - { - "events": [ - { - "event_name": "payment_processed", - "timestamp": "2022-03-24T07:15:00Z", - "properties": { - "amount": 100 - } - }, - { - "event_name": "payment_failed", - "timestamp": "2022-03-24T07:15:00Z", - "properties": { - "amount": 100 - } - } - ] - } - ``` - - ## Request Validation - - - The `timestamp` of each event reported must fall within the bounds of - `timeframe_start` and `timeframe_end`. As with ingestion, all timesta mps must - be sent in ISO8601 format with UTC timezone offset. - - Orb **does not accept an `idempotency_key`** with each event in this endpoint, - since the entirety of the event list must be ingested to ensure consistency. - On retryable errors , you should retry the request in its entirety, and assume - that the amendment operation has not succeeded until receipt of a `2xx`. - - - Both `timeframe_start` and `timeframe_end` must be timestamps in the past. - Furthermore, Orb will genera lly validate that the `timeframe_start` and - `timeframe_end` fall within the customer's _current_ subscription billing pe - riod. However, Orb does allow amendments while in the grace period of the - previous billing period; in this instance, the timeframe can start before the - current period. - - ## API Limits - - Note that Orb does not currently enforce a hard rate- limit for API usage or a - maximum request payload size. Similar to the event ingestion API, this API is - architected for h igh-throughput ingestion. It is also safe to - _programmatically_ call this endpoint if your system can automatically dete ct a - need for historical amendment. - - In order to overwrite timeframes with a very large number of events, we suggest - using multiple calls with small adjacent (e.g. every hour) timeframes. - - Args: - events: Events to update - - timeframe_end: This bound is exclusive (i.e. events before this timestamp will be updated) - - timeframe_start: This bound is inclusive (i.e. events with this timestamp onward, inclusive will - be updated) - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._patch( - f"/customers/{id}/usage", - body=maybe_transform({"events": events}, usage_update_params.UsageUpdateParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - query=maybe_transform( - { - "timeframe_end": timeframe_end, - "timeframe_start": timeframe_start, - }, - usage_update_params.UsageUpdateParams, - ), - ), - cast_to=UsageUpdateResponse, - ) - - def update_by_external_id( - self, - id: Optional[str], - *, - events: Iterable[usage_update_by_external_id_params.Event], - timeframe_end: Union[str, datetime] | NotGiven = NOT_GIVEN, - timeframe_start: 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, - idempotency_key: str | None = None, - ) -> UsageUpdateByExternalIDResponse: - """ - This endpoint is used to amend usage within a timeframe for a customer that has - an active subscription. - - This endpoint will mark _all_ existing events within - `[timeframe_start, timeframe_end)` as _ignored_ for billing purposes, and Orb - will only use the _new_ events passed in the body of this request as the source - of truth for that timeframe moving forwards. Note that a given time period can - be amended any number of times, so events can be overwritten in subsequent calls - to th is endpoint. - - This is a powerful and audit-safe mechanism to retroactively change usage data - in cases where you need to: - - - decrease historical usage consumption because of degraded service availability - in your systems - - account for gaps from your usage reporting mechanism - - make point-in-time fixes for specific event records, while retaining the - original time of usage and associated metadata. This amendment API is designed - with two explicit goals: - - 1. Amendments are **always audit-safe**. The amendment process will still retain - original events in the timeframe, though they will be ignored for billing - calculations. For auditing a nd data fidelity purposes, Orb never overwrites - or permanently deletes ingested usage data. - 2. Amendments always preserve data **consistency**. In other words, either an - amendment is fully processed by the system (and the new events for the - timeframe are honored rather than the existing ones) or the amendment request - fails. To maintain this important property, Orb prevents _partial event - ingestion_ on this endpoint. - - ## Response semantics - - - Either all events are ingested successfully, or all fail to ingest (returning - a `4xx` or `5xx` response code). - - Any event that fails schema validation will lead to a `4xx` response. In this - case, to maintain data consistency, Orb will not ingest any events and will - also not deprecate existing events in the time period. - - You can assume that the amendment is successful on receipt of a `2xx` - response.While a successful response from this endpoint indicates that the new - events have been ingested, updating usage totals happens asynchronously and - may be delayed by a few minutes. - - As emphasized above, Orb will never show an inconsistent state (e.g. in invoice - previews or dashboards); either it will show the existing state (before the - amendment) or the new state (with new events in the requested timeframe). - - ## Sample request body - - ```json - { - "events": [ - { - "event_name": "payment_processed", - "timestamp": "2022-03-24T07:15:00Z", - "properties": { - "amount": 100 - } - }, - { - "event_name": "payment_failed", - "timestamp": "2022-03-24T07:15:00Z", - "properties": { - "amount": 100 - } - } - ] - } - ``` - - ## Request Validation - - - The `timestamp` of each event reported must fall within the bounds of - `timeframe_start` and `timeframe_end`. As with ingestion, all timesta mps must - be sent in ISO8601 format with UTC timezone offset. - - Orb **does not accept an `idempotency_key`** with each event in this endpoint, - since the entirety of the event list must be ingested to ensure consistency. - On retryable errors , you should retry the request in its entirety, and assume - that the amendment operation has not succeeded until receipt of a `2xx`. - - - Both `timeframe_start` and `timeframe_end` must be timestamps in the past. - Furthermore, Orb will genera lly validate that the `timeframe_start` and - `timeframe_end` fall within the customer's _current_ subscription billing pe - riod. However, Orb does allow amendments while in the grace period of the - previous billing period; in this instance, the timeframe can start before the - current period. - - ## API Limits - - Note that Orb does not currently enforce a hard rate- limit for API usage or a - maximum request payload size. Similar to the event ingestion API, this API is - architected for h igh-throughput ingestion. It is also safe to - _programmatically_ call this endpoint if your system can automatically dete ct a - need for historical amendment. - - In order to overwrite timeframes with a very large number of events, we suggest - using multiple calls with small adjacent (e.g. every hour) timeframes. - - Args: - events: Events to update - - timeframe_end: This bound is exclusive (i.e. events before this timestamp will be updated) - - timeframe_start: This bound is inclusive (i.e. events with this timestamp onward, inclusive will - be updated) - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._patch( - f"/customers/external_customer_id/{id}/usage", - body=maybe_transform({"events": events}, usage_update_by_external_id_params.UsageUpdateByExternalIDParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - query=maybe_transform( - { - "timeframe_end": timeframe_end, - "timeframe_start": timeframe_start, - }, - usage_update_by_external_id_params.UsageUpdateByExternalIDParams, - ), - ), - cast_to=UsageUpdateByExternalIDResponse, - ) - - -class AsyncUsage(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncUsageWithRawResponse: - return AsyncUsageWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncUsageWithStreamingResponse: - return AsyncUsageWithStreamingResponse(self) - - async def update( - self, - id: Optional[str], - *, - events: Iterable[usage_update_params.Event], - timeframe_end: Union[str, datetime] | NotGiven = NOT_GIVEN, - timeframe_start: 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, - idempotency_key: str | None = None, - ) -> UsageUpdateResponse: - """ - This endpoint is used to amend usage within a timeframe for a customer that has - an active subscription. - - This endpoint will mark _all_ existing events within - `[timeframe_start, timeframe_end)` as _ignored_ for billing purposes, and Orb - will only use the _new_ events passed in the body of this request as the source - of truth for that timeframe moving forwards. Note that a given time period can - be amended any number of times, so events can be overwritten in subsequent calls - to th is endpoint. - - This is a powerful and audit-safe mechanism to retroactively change usage data - in cases where you need to: - - - decrease historical usage consumption because of degraded service availability - in your systems - - account for gaps from your usage reporting mechanism - - make point-in-time fixes for specific event records, while retaining the - original time of usage and associated metadata. This amendment API is designed - with two explicit goals: - - 1. Amendments are **always audit-safe**. The amendment process will still retain - original events in the timeframe, though they will be ignored for billing - calculations. For auditing a nd data fidelity purposes, Orb never overwrites - or permanently deletes ingested usage data. - 2. Amendments always preserve data **consistency**. In other words, either an - amendment is fully processed by the system (and the new events for the - timeframe are honored rather than the existing ones) or the amendment request - fails. To maintain this important property, Orb prevents _partial event - ingestion_ on this endpoint. - - ## Response semantics - - - Either all events are ingested successfully, or all fail to ingest (returning - a `4xx` or `5xx` response code). - - Any event that fails schema validation will lead to a `4xx` response. In this - case, to maintain data consistency, Orb will not ingest any events and will - also not deprecate existing events in the time period. - - You can assume that the amendment is successful on receipt of a `2xx` - response.While a successful response from this endpoint indicates that the new - events have been ingested, updating usage totals happens asynchronously and - may be delayed by a few minutes. - - As emphasized above, Orb will never show an inconsistent state (e.g. in invoice - previews or dashboards); either it will show the existing state (before the - amendment) or the new state (with new events in the requested timeframe). - - ## Sample request body - - ```json - { - "events": [ - { - "event_name": "payment_processed", - "timestamp": "2022-03-24T07:15:00Z", - "properties": { - "amount": 100 - } - }, - { - "event_name": "payment_failed", - "timestamp": "2022-03-24T07:15:00Z", - "properties": { - "amount": 100 - } - } - ] - } - ``` - - ## Request Validation - - - The `timestamp` of each event reported must fall within the bounds of - `timeframe_start` and `timeframe_end`. As with ingestion, all timesta mps must - be sent in ISO8601 format with UTC timezone offset. - - Orb **does not accept an `idempotency_key`** with each event in this endpoint, - since the entirety of the event list must be ingested to ensure consistency. - On retryable errors , you should retry the request in its entirety, and assume - that the amendment operation has not succeeded until receipt of a `2xx`. - - - Both `timeframe_start` and `timeframe_end` must be timestamps in the past. - Furthermore, Orb will genera lly validate that the `timeframe_start` and - `timeframe_end` fall within the customer's _current_ subscription billing pe - riod. However, Orb does allow amendments while in the grace period of the - previous billing period; in this instance, the timeframe can start before the - current period. - - ## API Limits - - Note that Orb does not currently enforce a hard rate- limit for API usage or a - maximum request payload size. Similar to the event ingestion API, this API is - architected for h igh-throughput ingestion. It is also safe to - _programmatically_ call this endpoint if your system can automatically dete ct a - need for historical amendment. - - In order to overwrite timeframes with a very large number of events, we suggest - using multiple calls with small adjacent (e.g. every hour) timeframes. - - Args: - events: Events to update - - timeframe_end: This bound is exclusive (i.e. events before this timestamp will be updated) - - timeframe_start: This bound is inclusive (i.e. events with this timestamp onward, inclusive will - be updated) - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._patch( - f"/customers/{id}/usage", - body=await async_maybe_transform({"events": events}, usage_update_params.UsageUpdateParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - query=await async_maybe_transform( - { - "timeframe_end": timeframe_end, - "timeframe_start": timeframe_start, - }, - usage_update_params.UsageUpdateParams, - ), - ), - cast_to=UsageUpdateResponse, - ) - - async def update_by_external_id( - self, - id: Optional[str], - *, - events: Iterable[usage_update_by_external_id_params.Event], - timeframe_end: Union[str, datetime] | NotGiven = NOT_GIVEN, - timeframe_start: 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, - idempotency_key: str | None = None, - ) -> UsageUpdateByExternalIDResponse: - """ - This endpoint is used to amend usage within a timeframe for a customer that has - an active subscription. - - This endpoint will mark _all_ existing events within - `[timeframe_start, timeframe_end)` as _ignored_ for billing purposes, and Orb - will only use the _new_ events passed in the body of this request as the source - of truth for that timeframe moving forwards. Note that a given time period can - be amended any number of times, so events can be overwritten in subsequent calls - to th is endpoint. - - This is a powerful and audit-safe mechanism to retroactively change usage data - in cases where you need to: - - - decrease historical usage consumption because of degraded service availability - in your systems - - account for gaps from your usage reporting mechanism - - make point-in-time fixes for specific event records, while retaining the - original time of usage and associated metadata. This amendment API is designed - with two explicit goals: - - 1. Amendments are **always audit-safe**. The amendment process will still retain - original events in the timeframe, though they will be ignored for billing - calculations. For auditing a nd data fidelity purposes, Orb never overwrites - or permanently deletes ingested usage data. - 2. Amendments always preserve data **consistency**. In other words, either an - amendment is fully processed by the system (and the new events for the - timeframe are honored rather than the existing ones) or the amendment request - fails. To maintain this important property, Orb prevents _partial event - ingestion_ on this endpoint. - - ## Response semantics - - - Either all events are ingested successfully, or all fail to ingest (returning - a `4xx` or `5xx` response code). - - Any event that fails schema validation will lead to a `4xx` response. In this - case, to maintain data consistency, Orb will not ingest any events and will - also not deprecate existing events in the time period. - - You can assume that the amendment is successful on receipt of a `2xx` - response.While a successful response from this endpoint indicates that the new - events have been ingested, updating usage totals happens asynchronously and - may be delayed by a few minutes. - - As emphasized above, Orb will never show an inconsistent state (e.g. in invoice - previews or dashboards); either it will show the existing state (before the - amendment) or the new state (with new events in the requested timeframe). - - ## Sample request body - - ```json - { - "events": [ - { - "event_name": "payment_processed", - "timestamp": "2022-03-24T07:15:00Z", - "properties": { - "amount": 100 - } - }, - { - "event_name": "payment_failed", - "timestamp": "2022-03-24T07:15:00Z", - "properties": { - "amount": 100 - } - } - ] - } - ``` - - ## Request Validation - - - The `timestamp` of each event reported must fall within the bounds of - `timeframe_start` and `timeframe_end`. As with ingestion, all timesta mps must - be sent in ISO8601 format with UTC timezone offset. - - Orb **does not accept an `idempotency_key`** with each event in this endpoint, - since the entirety of the event list must be ingested to ensure consistency. - On retryable errors , you should retry the request in its entirety, and assume - that the amendment operation has not succeeded until receipt of a `2xx`. - - - Both `timeframe_start` and `timeframe_end` must be timestamps in the past. - Furthermore, Orb will genera lly validate that the `timeframe_start` and - `timeframe_end` fall within the customer's _current_ subscription billing pe - riod. However, Orb does allow amendments while in the grace period of the - previous billing period; in this instance, the timeframe can start before the - current period. - - ## API Limits - - Note that Orb does not currently enforce a hard rate- limit for API usage or a - maximum request payload size. Similar to the event ingestion API, this API is - architected for h igh-throughput ingestion. It is also safe to - _programmatically_ call this endpoint if your system can automatically dete ct a - need for historical amendment. - - In order to overwrite timeframes with a very large number of events, we suggest - using multiple calls with small adjacent (e.g. every hour) timeframes. - - Args: - events: Events to update - - timeframe_end: This bound is exclusive (i.e. events before this timestamp will be updated) - - timeframe_start: This bound is inclusive (i.e. events with this timestamp onward, inclusive will - be updated) - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._patch( - f"/customers/external_customer_id/{id}/usage", - body=await async_maybe_transform( - {"events": events}, usage_update_by_external_id_params.UsageUpdateByExternalIDParams - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - query=await async_maybe_transform( - { - "timeframe_end": timeframe_end, - "timeframe_start": timeframe_start, - }, - usage_update_by_external_id_params.UsageUpdateByExternalIDParams, - ), - ), - cast_to=UsageUpdateByExternalIDResponse, - ) - - -class UsageWithRawResponse: - def __init__(self, usage: Usage) -> None: - self._usage = usage - - self.update = _legacy_response.to_raw_response_wrapper( - usage.update, - ) - self.update_by_external_id = _legacy_response.to_raw_response_wrapper( - usage.update_by_external_id, - ) - - -class AsyncUsageWithRawResponse: - def __init__(self, usage: AsyncUsage) -> None: - self._usage = usage - - self.update = _legacy_response.async_to_raw_response_wrapper( - usage.update, - ) - self.update_by_external_id = _legacy_response.async_to_raw_response_wrapper( - usage.update_by_external_id, - ) - - -class UsageWithStreamingResponse: - def __init__(self, usage: Usage) -> None: - self._usage = usage - - self.update = to_streamed_response_wrapper( - usage.update, - ) - self.update_by_external_id = to_streamed_response_wrapper( - usage.update_by_external_id, - ) - - -class AsyncUsageWithStreamingResponse: - def __init__(self, usage: AsyncUsage) -> None: - self._usage = usage - - self.update = async_to_streamed_response_wrapper( - usage.update, - ) - self.update_by_external_id = async_to_streamed_response_wrapper( - usage.update_by_external_id, - ) diff --git a/src/orb/resources/dimensional_price_groups/__init__.py b/src/orb/resources/dimensional_price_groups/__init__.py new file mode 100644 index 00000000..d3533ab1 --- /dev/null +++ b/src/orb/resources/dimensional_price_groups/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .dimensional_price_groups import ( + DimensionalPriceGroups, + AsyncDimensionalPriceGroups, + DimensionalPriceGroupsWithRawResponse, + AsyncDimensionalPriceGroupsWithRawResponse, + DimensionalPriceGroupsWithStreamingResponse, + AsyncDimensionalPriceGroupsWithStreamingResponse, +) +from .external_dimensional_price_group_id import ( + ExternalDimensionalPriceGroupID, + AsyncExternalDimensionalPriceGroupID, + ExternalDimensionalPriceGroupIDWithRawResponse, + AsyncExternalDimensionalPriceGroupIDWithRawResponse, + ExternalDimensionalPriceGroupIDWithStreamingResponse, + AsyncExternalDimensionalPriceGroupIDWithStreamingResponse, +) + +__all__ = [ + "ExternalDimensionalPriceGroupID", + "AsyncExternalDimensionalPriceGroupID", + "ExternalDimensionalPriceGroupIDWithRawResponse", + "AsyncExternalDimensionalPriceGroupIDWithRawResponse", + "ExternalDimensionalPriceGroupIDWithStreamingResponse", + "AsyncExternalDimensionalPriceGroupIDWithStreamingResponse", + "DimensionalPriceGroups", + "AsyncDimensionalPriceGroups", + "DimensionalPriceGroupsWithRawResponse", + "AsyncDimensionalPriceGroupsWithRawResponse", + "DimensionalPriceGroupsWithStreamingResponse", + "AsyncDimensionalPriceGroupsWithStreamingResponse", +] diff --git a/src/orb/resources/dimensional_price_groups/dimensional_price_groups.py b/src/orb/resources/dimensional_price_groups/dimensional_price_groups.py new file mode 100644 index 00000000..1f0691df --- /dev/null +++ b/src/orb/resources/dimensional_price_groups/dimensional_price_groups.py @@ -0,0 +1,612 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional + +import httpx + +from ... import _legacy_response +from ...types import ( + dimensional_price_group_list_params, + dimensional_price_group_create_params, + dimensional_price_group_update_params, +) +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import path_template, 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 ...pagination import SyncPage, AsyncPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.dimensional_price_group import DimensionalPriceGroup +from .external_dimensional_price_group_id import ( + ExternalDimensionalPriceGroupID, + AsyncExternalDimensionalPriceGroupID, + ExternalDimensionalPriceGroupIDWithRawResponse, + AsyncExternalDimensionalPriceGroupIDWithRawResponse, + ExternalDimensionalPriceGroupIDWithStreamingResponse, + AsyncExternalDimensionalPriceGroupIDWithStreamingResponse, +) + +__all__ = ["DimensionalPriceGroups", "AsyncDimensionalPriceGroups"] + + +class DimensionalPriceGroups(SyncAPIResource): + @cached_property + def external_dimensional_price_group_id(self) -> ExternalDimensionalPriceGroupID: + return ExternalDimensionalPriceGroupID(self._client) + + @cached_property + def with_raw_response(self) -> DimensionalPriceGroupsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 DimensionalPriceGroupsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DimensionalPriceGroupsWithStreamingResponse: + """ + 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 DimensionalPriceGroupsWithStreamingResponse(self) + + def create( + self, + *, + billable_metric_id: str, + dimensions: SequenceNotStr[str], + name: str, + external_dimensional_price_group_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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, + ) -> DimensionalPriceGroup: + """ + A dimensional price group is used to partition the result of a billable metric + by a set of dimensions. Prices in a price group must specify the partition used + to derive their usage. + + For example, suppose we have a billable metric that measures the number of + widgets used and we want to charge differently depending on the color of the + widget. We can create a price group with a dimension "color" and two prices: one + that charges \\$$10 per red widget and one that charges \\$$20 per blue widget. + + Args: + dimensions: The set of keys (in order) used to disambiguate prices in the group. + + 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 + """ + return self._post( + "/dimensional_price_groups", + body=maybe_transform( + { + "billable_metric_id": billable_metric_id, + "dimensions": dimensions, + "name": name, + "external_dimensional_price_group_id": external_dimensional_price_group_id, + "metadata": metadata, + }, + dimensional_price_group_create_params.DimensionalPriceGroupCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=DimensionalPriceGroup, + ) + + def retrieve( + self, + dimensional_price_group_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DimensionalPriceGroup: + """ + Fetch dimensional price group + + Args: + 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 + """ + if not dimensional_price_group_id: + raise ValueError( + f"Expected a non-empty value for `dimensional_price_group_id` but received {dimensional_price_group_id!r}" + ) + return self._get( + path_template( + "/dimensional_price_groups/{dimensional_price_group_id}", + dimensional_price_group_id=dimensional_price_group_id, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DimensionalPriceGroup, + ) + + def update( + self, + dimensional_price_group_id: str, + *, + external_dimensional_price_group_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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, + ) -> DimensionalPriceGroup: + """ + This endpoint can be used to update the `external_dimensional_price_group_id` + and `metadata` of an existing dimensional price group. Other fields on a + dimensional price group are currently immutable. + + Args: + external_dimensional_price_group_id: An optional user-defined ID for this dimensional price group resource, used + throughout the system as an alias for this dimensional price group. Use this + field to identify a dimensional price group by an existing identifier in your + system. + + 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 + """ + if not dimensional_price_group_id: + raise ValueError( + f"Expected a non-empty value for `dimensional_price_group_id` but received {dimensional_price_group_id!r}" + ) + return self._put( + path_template( + "/dimensional_price_groups/{dimensional_price_group_id}", + dimensional_price_group_id=dimensional_price_group_id, + ), + body=maybe_transform( + { + "external_dimensional_price_group_id": external_dimensional_price_group_id, + "metadata": metadata, + }, + dimensional_price_group_update_params.DimensionalPriceGroupUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=DimensionalPriceGroup, + ) + + def list( + self, + *, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + # 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, + ) -> SyncPage[DimensionalPriceGroup]: + """List dimensional price groups + + Args: + 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. + + 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_api_list( + "/dimensional_price_groups", + page=SyncPage[DimensionalPriceGroup], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "cursor": cursor, + "limit": limit, + }, + dimensional_price_group_list_params.DimensionalPriceGroupListParams, + ), + ), + model=DimensionalPriceGroup, + ) + + +class AsyncDimensionalPriceGroups(AsyncAPIResource): + @cached_property + def external_dimensional_price_group_id(self) -> AsyncExternalDimensionalPriceGroupID: + return AsyncExternalDimensionalPriceGroupID(self._client) + + @cached_property + def with_raw_response(self) -> AsyncDimensionalPriceGroupsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncDimensionalPriceGroupsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDimensionalPriceGroupsWithStreamingResponse: + """ + 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 AsyncDimensionalPriceGroupsWithStreamingResponse(self) + + async def create( + self, + *, + billable_metric_id: str, + dimensions: SequenceNotStr[str], + name: str, + external_dimensional_price_group_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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, + ) -> DimensionalPriceGroup: + """ + A dimensional price group is used to partition the result of a billable metric + by a set of dimensions. Prices in a price group must specify the partition used + to derive their usage. + + For example, suppose we have a billable metric that measures the number of + widgets used and we want to charge differently depending on the color of the + widget. We can create a price group with a dimension "color" and two prices: one + that charges \\$$10 per red widget and one that charges \\$$20 per blue widget. + + Args: + dimensions: The set of keys (in order) used to disambiguate prices in the group. + + 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 + """ + return await self._post( + "/dimensional_price_groups", + body=await async_maybe_transform( + { + "billable_metric_id": billable_metric_id, + "dimensions": dimensions, + "name": name, + "external_dimensional_price_group_id": external_dimensional_price_group_id, + "metadata": metadata, + }, + dimensional_price_group_create_params.DimensionalPriceGroupCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=DimensionalPriceGroup, + ) + + async def retrieve( + self, + dimensional_price_group_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DimensionalPriceGroup: + """ + Fetch dimensional price group + + Args: + 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 + """ + if not dimensional_price_group_id: + raise ValueError( + f"Expected a non-empty value for `dimensional_price_group_id` but received {dimensional_price_group_id!r}" + ) + return await self._get( + path_template( + "/dimensional_price_groups/{dimensional_price_group_id}", + dimensional_price_group_id=dimensional_price_group_id, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DimensionalPriceGroup, + ) + + async def update( + self, + dimensional_price_group_id: str, + *, + external_dimensional_price_group_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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, + ) -> DimensionalPriceGroup: + """ + This endpoint can be used to update the `external_dimensional_price_group_id` + and `metadata` of an existing dimensional price group. Other fields on a + dimensional price group are currently immutable. + + Args: + external_dimensional_price_group_id: An optional user-defined ID for this dimensional price group resource, used + throughout the system as an alias for this dimensional price group. Use this + field to identify a dimensional price group by an existing identifier in your + system. + + 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 + """ + if not dimensional_price_group_id: + raise ValueError( + f"Expected a non-empty value for `dimensional_price_group_id` but received {dimensional_price_group_id!r}" + ) + return await self._put( + path_template( + "/dimensional_price_groups/{dimensional_price_group_id}", + dimensional_price_group_id=dimensional_price_group_id, + ), + body=await async_maybe_transform( + { + "external_dimensional_price_group_id": external_dimensional_price_group_id, + "metadata": metadata, + }, + dimensional_price_group_update_params.DimensionalPriceGroupUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=DimensionalPriceGroup, + ) + + def list( + self, + *, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + # 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, + ) -> AsyncPaginator[DimensionalPriceGroup, AsyncPage[DimensionalPriceGroup]]: + """List dimensional price groups + + Args: + 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. + + 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_api_list( + "/dimensional_price_groups", + page=AsyncPage[DimensionalPriceGroup], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "cursor": cursor, + "limit": limit, + }, + dimensional_price_group_list_params.DimensionalPriceGroupListParams, + ), + ), + model=DimensionalPriceGroup, + ) + + +class DimensionalPriceGroupsWithRawResponse: + def __init__(self, dimensional_price_groups: DimensionalPriceGroups) -> None: + self._dimensional_price_groups = dimensional_price_groups + + self.create = _legacy_response.to_raw_response_wrapper( + dimensional_price_groups.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + dimensional_price_groups.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + dimensional_price_groups.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + dimensional_price_groups.list, + ) + + @cached_property + def external_dimensional_price_group_id(self) -> ExternalDimensionalPriceGroupIDWithRawResponse: + return ExternalDimensionalPriceGroupIDWithRawResponse( + self._dimensional_price_groups.external_dimensional_price_group_id + ) + + +class AsyncDimensionalPriceGroupsWithRawResponse: + def __init__(self, dimensional_price_groups: AsyncDimensionalPriceGroups) -> None: + self._dimensional_price_groups = dimensional_price_groups + + self.create = _legacy_response.async_to_raw_response_wrapper( + dimensional_price_groups.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + dimensional_price_groups.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + dimensional_price_groups.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + dimensional_price_groups.list, + ) + + @cached_property + def external_dimensional_price_group_id(self) -> AsyncExternalDimensionalPriceGroupIDWithRawResponse: + return AsyncExternalDimensionalPriceGroupIDWithRawResponse( + self._dimensional_price_groups.external_dimensional_price_group_id + ) + + +class DimensionalPriceGroupsWithStreamingResponse: + def __init__(self, dimensional_price_groups: DimensionalPriceGroups) -> None: + self._dimensional_price_groups = dimensional_price_groups + + self.create = to_streamed_response_wrapper( + dimensional_price_groups.create, + ) + self.retrieve = to_streamed_response_wrapper( + dimensional_price_groups.retrieve, + ) + self.update = to_streamed_response_wrapper( + dimensional_price_groups.update, + ) + self.list = to_streamed_response_wrapper( + dimensional_price_groups.list, + ) + + @cached_property + def external_dimensional_price_group_id(self) -> ExternalDimensionalPriceGroupIDWithStreamingResponse: + return ExternalDimensionalPriceGroupIDWithStreamingResponse( + self._dimensional_price_groups.external_dimensional_price_group_id + ) + + +class AsyncDimensionalPriceGroupsWithStreamingResponse: + def __init__(self, dimensional_price_groups: AsyncDimensionalPriceGroups) -> None: + self._dimensional_price_groups = dimensional_price_groups + + self.create = async_to_streamed_response_wrapper( + dimensional_price_groups.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + dimensional_price_groups.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + dimensional_price_groups.update, + ) + self.list = async_to_streamed_response_wrapper( + dimensional_price_groups.list, + ) + + @cached_property + def external_dimensional_price_group_id(self) -> AsyncExternalDimensionalPriceGroupIDWithStreamingResponse: + return AsyncExternalDimensionalPriceGroupIDWithStreamingResponse( + self._dimensional_price_groups.external_dimensional_price_group_id + ) diff --git a/src/orb/resources/dimensional_price_groups/external_dimensional_price_group_id.py b/src/orb/resources/dimensional_price_groups/external_dimensional_price_group_id.py new file mode 100644 index 00000000..1e3bf12d --- /dev/null +++ b/src/orb/resources/dimensional_price_groups/external_dimensional_price_group_id.py @@ -0,0 +1,315 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional + +import httpx + +from ... import _legacy_response +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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.dimensional_price_group import DimensionalPriceGroup +from ...types.dimensional_price_groups import external_dimensional_price_group_id_update_params + +__all__ = ["ExternalDimensionalPriceGroupID", "AsyncExternalDimensionalPriceGroupID"] + + +class ExternalDimensionalPriceGroupID(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ExternalDimensionalPriceGroupIDWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 ExternalDimensionalPriceGroupIDWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ExternalDimensionalPriceGroupIDWithStreamingResponse: + """ + 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 ExternalDimensionalPriceGroupIDWithStreamingResponse(self) + + def retrieve( + self, + external_dimensional_price_group_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DimensionalPriceGroup: + """ + Fetch dimensional price group by external ID + + Args: + 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 + """ + if not external_dimensional_price_group_id: + raise ValueError( + f"Expected a non-empty value for `external_dimensional_price_group_id` but received {external_dimensional_price_group_id!r}" + ) + return self._get( + path_template( + "/dimensional_price_groups/external_dimensional_price_group_id/{external_dimensional_price_group_id}", + external_dimensional_price_group_id=external_dimensional_price_group_id, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DimensionalPriceGroup, + ) + + def update( + self, + path_external_dimensional_price_group_id: str, + *, + body_external_dimensional_price_group_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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, + ) -> DimensionalPriceGroup: + """ + This endpoint can be used to update the `external_dimensional_price_group_id` + and `metadata` of an existing dimensional price group. Other fields on a + dimensional price group are currently immutable. + + Args: + body_external_dimensional_price_group_id: An optional user-defined ID for this dimensional price group resource, used + throughout the system as an alias for this dimensional price group. Use this + field to identify a dimensional price group by an existing identifier in your + system. + + 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 + """ + if not path_external_dimensional_price_group_id: + raise ValueError( + f"Expected a non-empty value for `path_external_dimensional_price_group_id` but received {path_external_dimensional_price_group_id!r}" + ) + return self._put( + path_template( + "/dimensional_price_groups/external_dimensional_price_group_id/{path_external_dimensional_price_group_id}", + path_external_dimensional_price_group_id=path_external_dimensional_price_group_id, + ), + body=maybe_transform( + { + "body_external_dimensional_price_group_id": body_external_dimensional_price_group_id, + "metadata": metadata, + }, + external_dimensional_price_group_id_update_params.ExternalDimensionalPriceGroupIDUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=DimensionalPriceGroup, + ) + + +class AsyncExternalDimensionalPriceGroupID(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncExternalDimensionalPriceGroupIDWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncExternalDimensionalPriceGroupIDWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncExternalDimensionalPriceGroupIDWithStreamingResponse: + """ + 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 AsyncExternalDimensionalPriceGroupIDWithStreamingResponse(self) + + async def retrieve( + self, + external_dimensional_price_group_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DimensionalPriceGroup: + """ + Fetch dimensional price group by external ID + + Args: + 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 + """ + if not external_dimensional_price_group_id: + raise ValueError( + f"Expected a non-empty value for `external_dimensional_price_group_id` but received {external_dimensional_price_group_id!r}" + ) + return await self._get( + path_template( + "/dimensional_price_groups/external_dimensional_price_group_id/{external_dimensional_price_group_id}", + external_dimensional_price_group_id=external_dimensional_price_group_id, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DimensionalPriceGroup, + ) + + async def update( + self, + path_external_dimensional_price_group_id: str, + *, + body_external_dimensional_price_group_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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, + ) -> DimensionalPriceGroup: + """ + This endpoint can be used to update the `external_dimensional_price_group_id` + and `metadata` of an existing dimensional price group. Other fields on a + dimensional price group are currently immutable. + + Args: + body_external_dimensional_price_group_id: An optional user-defined ID for this dimensional price group resource, used + throughout the system as an alias for this dimensional price group. Use this + field to identify a dimensional price group by an existing identifier in your + system. + + 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 + """ + if not path_external_dimensional_price_group_id: + raise ValueError( + f"Expected a non-empty value for `path_external_dimensional_price_group_id` but received {path_external_dimensional_price_group_id!r}" + ) + return await self._put( + path_template( + "/dimensional_price_groups/external_dimensional_price_group_id/{path_external_dimensional_price_group_id}", + path_external_dimensional_price_group_id=path_external_dimensional_price_group_id, + ), + body=await async_maybe_transform( + { + "body_external_dimensional_price_group_id": body_external_dimensional_price_group_id, + "metadata": metadata, + }, + external_dimensional_price_group_id_update_params.ExternalDimensionalPriceGroupIDUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=DimensionalPriceGroup, + ) + + +class ExternalDimensionalPriceGroupIDWithRawResponse: + def __init__(self, external_dimensional_price_group_id: ExternalDimensionalPriceGroupID) -> None: + self._external_dimensional_price_group_id = external_dimensional_price_group_id + + self.retrieve = _legacy_response.to_raw_response_wrapper( + external_dimensional_price_group_id.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + external_dimensional_price_group_id.update, + ) + + +class AsyncExternalDimensionalPriceGroupIDWithRawResponse: + def __init__(self, external_dimensional_price_group_id: AsyncExternalDimensionalPriceGroupID) -> None: + self._external_dimensional_price_group_id = external_dimensional_price_group_id + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + external_dimensional_price_group_id.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + external_dimensional_price_group_id.update, + ) + + +class ExternalDimensionalPriceGroupIDWithStreamingResponse: + def __init__(self, external_dimensional_price_group_id: ExternalDimensionalPriceGroupID) -> None: + self._external_dimensional_price_group_id = external_dimensional_price_group_id + + self.retrieve = to_streamed_response_wrapper( + external_dimensional_price_group_id.retrieve, + ) + self.update = to_streamed_response_wrapper( + external_dimensional_price_group_id.update, + ) + + +class AsyncExternalDimensionalPriceGroupIDWithStreamingResponse: + def __init__(self, external_dimensional_price_group_id: AsyncExternalDimensionalPriceGroupID) -> None: + self._external_dimensional_price_group_id = external_dimensional_price_group_id + + self.retrieve = async_to_streamed_response_wrapper( + external_dimensional_price_group_id.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + external_dimensional_price_group_id.update, + ) 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 96e5ef57..1bfd66e7 100644 --- a/src/orb/resources/events/backfills.py +++ b/src/orb/resources/events/backfills.py @@ -8,39 +8,47 @@ import httpx from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import ( - maybe_transform, - async_maybe_transform, -) +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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 ...pagination import SyncPage, AsyncPage -from ..._base_client import ( - AsyncPaginator, - make_request_options, -) -from ...types.events import ( - BackfillListResponse, - BackfillCloseResponse, - BackfillFetchResponse, - BackfillCreateResponse, - BackfillRevertResponse, - backfill_list_params, - backfill_create_params, -) +from ..._base_client import AsyncPaginator, make_request_options +from ...types.events import backfill_list_params, backfill_create_params +from ...types.events.backfill_list_response import BackfillListResponse +from ...types.events.backfill_close_response import BackfillCloseResponse +from ...types.events.backfill_fetch_response import BackfillFetchResponse +from ...types.events.backfill_create_response import BackfillCreateResponse +from ...types.events.backfill_revert_response import BackfillRevertResponse __all__ = ["Backfills", "AsyncBackfills"] class Backfills(SyncAPIResource): + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + @cached_property def with_raw_response(self) -> BackfillsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -48,16 +56,17 @@ def create( *, timeframe_end: Union[str, datetime], timeframe_start: Union[str, datetime], - close_time: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - customer_id: Optional[str] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - replace_existing_events: bool | NotGiven = NOT_GIVEN, + close_time: Union[str, datetime, None] | Omit = omit, + customer_id: Optional[str] | Omit = omit, + deprecation_filter: Optional[str] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + replace_existing_events: bool | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> BackfillCreateResponse: """ @@ -66,8 +75,8 @@ def create( 3 steps: 1. Create the backfill, specifying its parameters. - 2. [Ingest](ingest) usage events, referencing the backfill (query parameter - `backfill_id`). + 2. [Ingest](/api-reference/event/ingest-events) usage events, referencing the + backfill (query parameter `backfill_id`). 3. [Close](close-backfill) the backfill, propagating the update in past usage throughout Orb. @@ -87,18 +96,43 @@ def create( backfill. If `false`, newly ingested events will be added to the existing events. + If a `customer_id` or `external_customer_id` is specified, the backfill will + only affect events for that customer. If neither is specified, the backfill will + affect all customers. + + When `replace_existing_events` is `true`, this indicates that existing events in + the timeframe should no longer be counted towards invoiced usage. In this + scenario, the parameter `deprecation_filter` can be optionally added which + enables filtering using + [computed properties](/extensibility/advanced-metrics#computed-properties). The + expressiveness of computed properties allows you to deprecate existing events + based on both a period of time and specific property values. + + You may not have multiple backfills in a pending or pending_revert state with + overlapping timeframes. + Args: - timeframe_end: The (exclusive) end of the usage timeframe affected by this backfill. + timeframe_end: The (exclusive) end of the usage timeframe affected by this backfill. By + default, Orb allows backfills up to 31 days in duration at a time. Reach out to + discuss extending this limit and your use case. - timeframe_start: The (inclusive) start of the usage timeframe affected by this backfill. + timeframe_start: The (inclusive) start of the usage timeframe affected by this backfill. By + default, Orb allows backfills up to 31 days in duration at a time. Reach out to + discuss extending this limit and your use case. close_time: The time at which no more events will be accepted for this backfill. The 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](/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. @@ -121,6 +155,7 @@ def create( "timeframe_start": timeframe_start, "close_time": close_time, "customer_id": customer_id, + "deprecation_filter": deprecation_filter, "external_customer_id": external_customer_id, "replace_existing_events": replace_existing_events, }, @@ -139,23 +174,22 @@ def create( def list( self, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[BackfillListResponse]: """ This endpoint returns a list of all backfills in a list format. The list of backfills is ordered starting from the most recently created backfill. The response also includes - [`pagination_metadata`](../reference/pagination), which lets the caller retrieve - the next page of results if they exist. More information about pagination can be - found in the [Pagination-metadata schema](pagination). + [`pagination_metadata`](/api-reference/pagination), which lets the caller + retrieve the next page of results if they exist. Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -199,7 +233,7 @@ def close( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> BackfillCloseResponse: """Closing a backfill makes the updated usage visible in Orb. @@ -223,7 +257,7 @@ def close( if not backfill_id: raise ValueError(f"Expected a non-empty value for `backfill_id` but received {backfill_id!r}") return self._post( - f"/events/backfills/{backfill_id}/close", + path_template("/events/backfills/{backfill_id}/close", backfill_id=backfill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -243,7 +277,7 @@ def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> BackfillFetchResponse: """ This endpoint is used to fetch a backfill given an identifier. @@ -260,7 +294,7 @@ def fetch( if not backfill_id: raise ValueError(f"Expected a non-empty value for `backfill_id` but received {backfill_id!r}") return self._get( - f"/events/backfills/{backfill_id}", + path_template("/events/backfills/{backfill_id}", backfill_id=backfill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -276,7 +310,7 @@ def revert( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> BackfillRevertResponse: """Reverting a backfill undoes all the effects of closing the backfill. @@ -303,7 +337,7 @@ def revert( if not backfill_id: raise ValueError(f"Expected a non-empty value for `backfill_id` but received {backfill_id!r}") return self._post( - f"/events/backfills/{backfill_id}/revert", + path_template("/events/backfills/{backfill_id}/revert", backfill_id=backfill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -316,12 +350,29 @@ def revert( class AsyncBackfills(AsyncAPIResource): + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + @cached_property def with_raw_response(self) -> AsyncBackfillsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -329,16 +380,17 @@ async def create( *, timeframe_end: Union[str, datetime], timeframe_start: Union[str, datetime], - close_time: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - customer_id: Optional[str] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - replace_existing_events: bool | NotGiven = NOT_GIVEN, + close_time: Union[str, datetime, None] | Omit = omit, + customer_id: Optional[str] | Omit = omit, + deprecation_filter: Optional[str] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + replace_existing_events: bool | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> BackfillCreateResponse: """ @@ -347,8 +399,8 @@ async def create( 3 steps: 1. Create the backfill, specifying its parameters. - 2. [Ingest](ingest) usage events, referencing the backfill (query parameter - `backfill_id`). + 2. [Ingest](/api-reference/event/ingest-events) usage events, referencing the + backfill (query parameter `backfill_id`). 3. [Close](close-backfill) the backfill, propagating the update in past usage throughout Orb. @@ -368,18 +420,43 @@ async def create( backfill. If `false`, newly ingested events will be added to the existing events. + If a `customer_id` or `external_customer_id` is specified, the backfill will + only affect events for that customer. If neither is specified, the backfill will + affect all customers. + + When `replace_existing_events` is `true`, this indicates that existing events in + the timeframe should no longer be counted towards invoiced usage. In this + scenario, the parameter `deprecation_filter` can be optionally added which + enables filtering using + [computed properties](/extensibility/advanced-metrics#computed-properties). The + expressiveness of computed properties allows you to deprecate existing events + based on both a period of time and specific property values. + + You may not have multiple backfills in a pending or pending_revert state with + overlapping timeframes. + Args: - timeframe_end: The (exclusive) end of the usage timeframe affected by this backfill. + timeframe_end: The (exclusive) end of the usage timeframe affected by this backfill. By + default, Orb allows backfills up to 31 days in duration at a time. Reach out to + discuss extending this limit and your use case. - timeframe_start: The (inclusive) start of the usage timeframe affected by this backfill. + timeframe_start: The (inclusive) start of the usage timeframe affected by this backfill. By + default, Orb allows backfills up to 31 days in duration at a time. Reach out to + discuss extending this limit and your use case. close_time: The time at which no more events will be accepted for this backfill. The 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](/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. @@ -402,6 +479,7 @@ async def create( "timeframe_start": timeframe_start, "close_time": close_time, "customer_id": customer_id, + "deprecation_filter": deprecation_filter, "external_customer_id": external_customer_id, "replace_existing_events": replace_existing_events, }, @@ -420,23 +498,22 @@ async def create( def list( self, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[BackfillListResponse, AsyncPage[BackfillListResponse]]: """ This endpoint returns a list of all backfills in a list format. The list of backfills is ordered starting from the most recently created backfill. The response also includes - [`pagination_metadata`](../reference/pagination), which lets the caller retrieve - the next page of results if they exist. More information about pagination can be - found in the [Pagination-metadata schema](pagination). + [`pagination_metadata`](/api-reference/pagination), which lets the caller + retrieve the next page of results if they exist. Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -480,7 +557,7 @@ async def close( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> BackfillCloseResponse: """Closing a backfill makes the updated usage visible in Orb. @@ -504,7 +581,7 @@ async def close( if not backfill_id: raise ValueError(f"Expected a non-empty value for `backfill_id` but received {backfill_id!r}") return await self._post( - f"/events/backfills/{backfill_id}/close", + path_template("/events/backfills/{backfill_id}/close", backfill_id=backfill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -524,7 +601,7 @@ async def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> BackfillFetchResponse: """ This endpoint is used to fetch a backfill given an identifier. @@ -541,7 +618,7 @@ async def fetch( if not backfill_id: raise ValueError(f"Expected a non-empty value for `backfill_id` but received {backfill_id!r}") return await self._get( - f"/events/backfills/{backfill_id}", + path_template("/events/backfills/{backfill_id}", backfill_id=backfill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -557,7 +634,7 @@ async def revert( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> BackfillRevertResponse: """Reverting a backfill undoes all the effects of closing the backfill. @@ -584,7 +661,7 @@ async def revert( if not backfill_id: raise ValueError(f"Expected a non-empty value for `backfill_id` but received {backfill_id!r}") return await self._post( - f"/events/backfills/{backfill_id}/revert", + path_template("/events/backfills/{backfill_id}/revert", backfill_id=backfill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/orb/resources/events/events.py b/src/orb/resources/events/events.py index b299a82a..0b44afc8 100644 --- a/src/orb/resources/events/events.py +++ b/src/orb/resources/events/events.py @@ -2,26 +2,23 @@ from __future__ import annotations -from typing import List, Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from datetime import datetime import httpx from ... import _legacy_response -from ...types import ( - EventIngestResponse, - EventSearchResponse, - EventUpdateResponse, - EventDeprecateResponse, - event_ingest_params, - event_search_params, - event_update_params, -) -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import ( - maybe_transform, - async_maybe_transform, +from .volume import ( + Volume, + AsyncVolume, + VolumeWithRawResponse, + AsyncVolumeWithRawResponse, + VolumeWithStreamingResponse, + AsyncVolumeWithStreamingResponse, ) +from ...types import event_ingest_params, event_search_params, event_update_params +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from .backfills import ( Backfills, @@ -33,24 +30,57 @@ ) 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 ..._base_client import make_request_options +from ...types.event_ingest_response import EventIngestResponse +from ...types.event_search_response import EventSearchResponse +from ...types.event_update_response import EventUpdateResponse +from ...types.event_deprecate_response import EventDeprecateResponse __all__ = ["Events", "AsyncEvents"] class Events(SyncAPIResource): + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + @cached_property def backfills(self) -> Backfills: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ return Backfills(self._client) + @cached_property + def volume(self) -> Volume: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + 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 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( @@ -58,16 +88,16 @@ def update( event_id: str, *, event_name: str, - properties: object, + properties: Dict[str, object], timestamp: Union[str, datetime], - customer_id: Optional[str] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, + customer_id: Optional[str] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> EventUpdateResponse: """ @@ -78,8 +108,7 @@ def update( This endpoint will mark the existing event as ignored, and Orb will only use the new event passed in the body of this request as the source of truth for that `event_id`. Note that a single event can be amended any number of times, so the - same event can be overwritten in subsequent calls to this endpoint, or - overwritten using the [Amend customer usage](amend-usage) endpoint. Only a + same event can be overwritten in subsequent calls to this endpoint. Only a single event with a given `event_id` will be considered the source of truth at any given time. @@ -114,6 +143,9 @@ def update( - The event's `timestamp` must fall within the customer's current subscription's billing period, or within the grace period of the customer's current subscription's previous billing period. + - By default, no more than 100 events can be amended for a single customer in a + 100 day period. For higher volume updates, consider using the + [event backfill](create-backfill) endpoint. Args: event_name: A name to meaningfully identify the action or event type. @@ -143,7 +175,7 @@ def update( if not event_id: raise ValueError(f"Expected a non-empty value for `event_id` but received {event_id!r}") return self._put( - f"/events/{event_id}", + path_template("/events/{event_id}", event_id=event_id), body=maybe_transform( { "event_name": event_name, @@ -173,7 +205,7 @@ def deprecate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> EventDeprecateResponse: """ @@ -192,8 +224,8 @@ def deprecate( call to a payment gateway failed and the user should not be billed) If you want to only change specific properties of an event, but keep the event - as part of the billing calculation, use the [Amend single event](amend-event) - endpoint instead. + as part of the billing calculation, use the [Amend event](amend-event) endpoint + instead. This API is always audit-safe. The process will still retain the deprecated event, though it will be ignored for billing calculations. For auditing and data @@ -214,6 +246,9 @@ def deprecate( ingestion request must identify a Customer resource within Orb, even if this event was ingested during the initial integration period. We do not allow deprecating events for customers not in the Orb system. + - By default, no more than 100 events can be deprecated for a single customer in + a 100 day period. For higher volume updates, consider using the + [event backfill](create-backfill) endpoint. Args: extra_headers: Send extra headers @@ -229,7 +264,7 @@ def deprecate( if not event_id: raise ValueError(f"Expected a non-empty value for `event_id` but received {event_id!r}") return self._put( - f"/events/{event_id}/deprecate", + path_template("/events/{event_id}/deprecate", event_id=event_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -244,14 +279,14 @@ def ingest( self, *, events: Iterable[event_ingest_params.Event], - backfill_id: Optional[str] | NotGiven = NOT_GIVEN, - debug: bool | NotGiven = NOT_GIVEN, + backfill_id: Optional[str] | Omit = omit, + debug: bool | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> EventIngestResponse: """Orb's event ingestion model and API is designed around two core principles: @@ -340,6 +375,8 @@ def ingest( flexible query engine to determine usage. - Logging a region or cluster with each event can help you provide customers more granular visibility into their usage. + - If you are using matrix pricing and matching a matrix price key with a + property, you should ensure the value for that property is sent as a string. We encourage logging this metadata with an eye towards future use cases to ensure full coverage for historical data. The datatype of the value in the @@ -368,6 +405,10 @@ def ingest( accurately map usage to the correct billing cycle and ensure that all usage is billed for in the corresponding billing period. + In general, Orb does not expect events with future dated timestamps. In cases + where the timestamp is 5 minutes ahead of the current time, the event will not + be accepted as a valid event, and will throw validation errors. + ## Event validation Orb’s validation ensures that you recognize errors in your events as quickly as @@ -377,22 +418,22 @@ def ingest( We validate the following: - Exactly one of `customer_id` and `external_customer_id` should be specified. - - If specified, `customer_id` must identify a Customer resource within Orb. We - do not support sending events for customers that have not been provisioned. - Similarly, if specified, `external_customer_id` must be an identifier that is - associated with an Orb Customer resource. Note: During our initial integration - period, this enforcement will be temporarily turned into a warning to ensure - smooth customer migration. - - `timestamp` must conform to ISO 8601 and represent a timestamp at most 1 hour - in the future. This timestamp should be sent in UTC timezone (no timezone - offset). + - If the `customer_id` is specified, the customer in Orb must exist. + - If the `external_customer_id` is specified, the customer in Orb does not need + to exist. Events will be attributed to any future customers with the + `external_customer_id` on subscription creation. + - `timestamp` must conform to ISO 8601 and represent a timestamp at most 5 + minutes in the future. This timestamp should be sent in UTC timezone (no + timezone offset). ## Idempotency and retry semantics Orb's idempotency guarantees allow you to implement safe retry logic in the event of network or machine failures, ensuring data fidelity. Each event in the request payload is associated with an idempotency key, and Orb guarantees that a - single idempotency key will be successfully ingested at most once. + single idempotency key will be successfully ingested at most once. Note that + when Orb encounters events with duplicate idempotency keys and differing event + bodies in a batch of events, the entire batch will be rejected. - Successful responses return a 200 HTTP status code. The response contains information about previously processed events. @@ -420,34 +461,7 @@ def ingest( request payload size, but please give us a heads up if you’re changing either of these factors by an order of magnitude from initial setup. - ## Testing in debug mode - - The ingestion API supports a debug mode, which returns additional verbose output - to indicate which event idempotency keys were newly ingested or duplicates from - previous requests. To enable this mode, mark `debug=true` as a query parameter. - - If `debug=true` is not specified, the response will only contain - `validation_failed`. Orb will still honor the idempotency guarantees set - [here](../guides/events-and-metrics/event-ingestion#event-volume-and-concurrency) - in all cases. - - We strongly recommend that you only use debug mode as part of testing your - initial Orb integration. Once you're ready to switch to production, disable - debug mode to take advantage of improved performance and maximal throughput. - - #### Example: ingestion response with `debug=true` - - ```json - { - "debug": { - "duplicate": [], - "ingested": ["B7E83HDMfJPAunXW", "SJs5DQJ3TnwSqEZE", "8SivfDsNKwCeAXim"] - }, - "validation_failed": [] - } - ``` - - #### Example: ingestion response with `debug=false` + #### Example: ingestion response ```json { @@ -459,7 +473,8 @@ def ingest( backfill_id: If this ingestion request is part of a backfill, this parameter ties the ingested events to the backfill - debug: Flag to enable additional debug information in the endpoint response + debug: Pending Deprecation: Flag to enable additional debug information in the endpoint + response extra_headers: Send extra headers @@ -494,20 +509,20 @@ def ingest( def search( self, *, - event_ids: List[str], - timeframe_end: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - timeframe_start: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + event_ids: SequenceNotStr[str], + timeframe_end: Union[str, datetime, None] | Omit = omit, + timeframe_start: Union[str, datetime, None] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> EventSearchResponse: """ This endpoint returns a filtered set of events for an account in a - [paginated list format](../reference/pagination). + [paginated list format](/api-reference/pagination). Note that this is a `POST` endpoint rather than a `GET` endpoint because it employs a JSON body for search criteria rather than query parameters, allowing @@ -566,16 +581,47 @@ def search( class AsyncEvents(AsyncAPIResource): + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + @cached_property def backfills(self) -> AsyncBackfills: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ return AsyncBackfills(self._client) + @cached_property + def volume(self) -> AsyncVolume: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + 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 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( @@ -583,16 +629,16 @@ async def update( event_id: str, *, event_name: str, - properties: object, + properties: Dict[str, object], timestamp: Union[str, datetime], - customer_id: Optional[str] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, + customer_id: Optional[str] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> EventUpdateResponse: """ @@ -603,8 +649,7 @@ async def update( This endpoint will mark the existing event as ignored, and Orb will only use the new event passed in the body of this request as the source of truth for that `event_id`. Note that a single event can be amended any number of times, so the - same event can be overwritten in subsequent calls to this endpoint, or - overwritten using the [Amend customer usage](amend-usage) endpoint. Only a + same event can be overwritten in subsequent calls to this endpoint. Only a single event with a given `event_id` will be considered the source of truth at any given time. @@ -639,6 +684,9 @@ async def update( - The event's `timestamp` must fall within the customer's current subscription's billing period, or within the grace period of the customer's current subscription's previous billing period. + - By default, no more than 100 events can be amended for a single customer in a + 100 day period. For higher volume updates, consider using the + [event backfill](create-backfill) endpoint. Args: event_name: A name to meaningfully identify the action or event type. @@ -668,7 +716,7 @@ async def update( if not event_id: raise ValueError(f"Expected a non-empty value for `event_id` but received {event_id!r}") return await self._put( - f"/events/{event_id}", + path_template("/events/{event_id}", event_id=event_id), body=await async_maybe_transform( { "event_name": event_name, @@ -698,7 +746,7 @@ async def deprecate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> EventDeprecateResponse: """ @@ -717,8 +765,8 @@ async def deprecate( call to a payment gateway failed and the user should not be billed) If you want to only change specific properties of an event, but keep the event - as part of the billing calculation, use the [Amend single event](amend-event) - endpoint instead. + as part of the billing calculation, use the [Amend event](amend-event) endpoint + instead. This API is always audit-safe. The process will still retain the deprecated event, though it will be ignored for billing calculations. For auditing and data @@ -739,6 +787,9 @@ async def deprecate( ingestion request must identify a Customer resource within Orb, even if this event was ingested during the initial integration period. We do not allow deprecating events for customers not in the Orb system. + - By default, no more than 100 events can be deprecated for a single customer in + a 100 day period. For higher volume updates, consider using the + [event backfill](create-backfill) endpoint. Args: extra_headers: Send extra headers @@ -754,7 +805,7 @@ async def deprecate( if not event_id: raise ValueError(f"Expected a non-empty value for `event_id` but received {event_id!r}") return await self._put( - f"/events/{event_id}/deprecate", + path_template("/events/{event_id}/deprecate", event_id=event_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -769,14 +820,14 @@ async def ingest( self, *, events: Iterable[event_ingest_params.Event], - backfill_id: Optional[str] | NotGiven = NOT_GIVEN, - debug: bool | NotGiven = NOT_GIVEN, + backfill_id: Optional[str] | Omit = omit, + debug: bool | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> EventIngestResponse: """Orb's event ingestion model and API is designed around two core principles: @@ -865,6 +916,8 @@ async def ingest( flexible query engine to determine usage. - Logging a region or cluster with each event can help you provide customers more granular visibility into their usage. + - If you are using matrix pricing and matching a matrix price key with a + property, you should ensure the value for that property is sent as a string. We encourage logging this metadata with an eye towards future use cases to ensure full coverage for historical data. The datatype of the value in the @@ -893,6 +946,10 @@ async def ingest( accurately map usage to the correct billing cycle and ensure that all usage is billed for in the corresponding billing period. + In general, Orb does not expect events with future dated timestamps. In cases + where the timestamp is 5 minutes ahead of the current time, the event will not + be accepted as a valid event, and will throw validation errors. + ## Event validation Orb’s validation ensures that you recognize errors in your events as quickly as @@ -902,22 +959,22 @@ async def ingest( We validate the following: - Exactly one of `customer_id` and `external_customer_id` should be specified. - - If specified, `customer_id` must identify a Customer resource within Orb. We - do not support sending events for customers that have not been provisioned. - Similarly, if specified, `external_customer_id` must be an identifier that is - associated with an Orb Customer resource. Note: During our initial integration - period, this enforcement will be temporarily turned into a warning to ensure - smooth customer migration. - - `timestamp` must conform to ISO 8601 and represent a timestamp at most 1 hour - in the future. This timestamp should be sent in UTC timezone (no timezone - offset). + - If the `customer_id` is specified, the customer in Orb must exist. + - If the `external_customer_id` is specified, the customer in Orb does not need + to exist. Events will be attributed to any future customers with the + `external_customer_id` on subscription creation. + - `timestamp` must conform to ISO 8601 and represent a timestamp at most 5 + minutes in the future. This timestamp should be sent in UTC timezone (no + timezone offset). ## Idempotency and retry semantics Orb's idempotency guarantees allow you to implement safe retry logic in the event of network or machine failures, ensuring data fidelity. Each event in the request payload is associated with an idempotency key, and Orb guarantees that a - single idempotency key will be successfully ingested at most once. + single idempotency key will be successfully ingested at most once. Note that + when Orb encounters events with duplicate idempotency keys and differing event + bodies in a batch of events, the entire batch will be rejected. - Successful responses return a 200 HTTP status code. The response contains information about previously processed events. @@ -945,34 +1002,7 @@ async def ingest( request payload size, but please give us a heads up if you’re changing either of these factors by an order of magnitude from initial setup. - ## Testing in debug mode - - The ingestion API supports a debug mode, which returns additional verbose output - to indicate which event idempotency keys were newly ingested or duplicates from - previous requests. To enable this mode, mark `debug=true` as a query parameter. - - If `debug=true` is not specified, the response will only contain - `validation_failed`. Orb will still honor the idempotency guarantees set - [here](../guides/events-and-metrics/event-ingestion#event-volume-and-concurrency) - in all cases. - - We strongly recommend that you only use debug mode as part of testing your - initial Orb integration. Once you're ready to switch to production, disable - debug mode to take advantage of improved performance and maximal throughput. - - #### Example: ingestion response with `debug=true` - - ```json - { - "debug": { - "duplicate": [], - "ingested": ["B7E83HDMfJPAunXW", "SJs5DQJ3TnwSqEZE", "8SivfDsNKwCeAXim"] - }, - "validation_failed": [] - } - ``` - - #### Example: ingestion response with `debug=false` + #### Example: ingestion response ```json { @@ -984,7 +1014,8 @@ async def ingest( backfill_id: If this ingestion request is part of a backfill, this parameter ties the ingested events to the backfill - debug: Flag to enable additional debug information in the endpoint response + debug: Pending Deprecation: Flag to enable additional debug information in the endpoint + response extra_headers: Send extra headers @@ -1019,20 +1050,20 @@ async def ingest( async def search( self, *, - event_ids: List[str], - timeframe_end: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - timeframe_start: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + event_ids: SequenceNotStr[str], + timeframe_end: Union[str, datetime, None] | Omit = omit, + timeframe_start: Union[str, datetime, None] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> EventSearchResponse: """ This endpoint returns a filtered set of events for an account in a - [paginated list format](../reference/pagination). + [paginated list format](/api-reference/pagination). Note that this is a `POST` endpoint rather than a `GET` endpoint because it employs a JSON body for search criteria rather than query parameters, allowing @@ -1109,8 +1140,22 @@ def __init__(self, events: Events) -> None: @cached_property def backfills(self) -> BackfillsWithRawResponse: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ return BackfillsWithRawResponse(self._events.backfills) + @cached_property + def volume(self) -> VolumeWithRawResponse: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + return VolumeWithRawResponse(self._events.volume) + class AsyncEventsWithRawResponse: def __init__(self, events: AsyncEvents) -> None: @@ -1131,8 +1176,22 @@ def __init__(self, events: AsyncEvents) -> None: @cached_property def backfills(self) -> AsyncBackfillsWithRawResponse: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ return AsyncBackfillsWithRawResponse(self._events.backfills) + @cached_property + def volume(self) -> AsyncVolumeWithRawResponse: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + return AsyncVolumeWithRawResponse(self._events.volume) + class EventsWithStreamingResponse: def __init__(self, events: Events) -> None: @@ -1153,8 +1212,22 @@ def __init__(self, events: Events) -> None: @cached_property def backfills(self) -> BackfillsWithStreamingResponse: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ return BackfillsWithStreamingResponse(self._events.backfills) + @cached_property + def volume(self) -> VolumeWithStreamingResponse: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + return VolumeWithStreamingResponse(self._events.volume) + class AsyncEventsWithStreamingResponse: def __init__(self, events: AsyncEvents) -> None: @@ -1175,4 +1248,18 @@ def __init__(self, events: AsyncEvents) -> None: @cached_property def backfills(self) -> AsyncBackfillsWithStreamingResponse: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ return AsyncBackfillsWithStreamingResponse(self._events.backfills) + + @cached_property + def volume(self) -> AsyncVolumeWithStreamingResponse: + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + 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..1342b46c --- /dev/null +++ b/src/orb/resources/events/volume.py @@ -0,0 +1,256 @@ +# 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 Body, Omit, Query, Headers, NotGiven, omit, not_given +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): + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + + @cached_property + def with_raw_response(self) -> VolumeWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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] | Omit = omit, + limit: int | Omit = omit, + timeframe_end: Union[str, datetime] | Omit = omit, + # 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](/api-reference/pagination). + + The event volume is aggregated by the hour and the + [timestamp](/api-reference/event/ingest-events) 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): + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + + @cached_property + def with_raw_response(self) -> AsyncVolumeWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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] | Omit = omit, + limit: int | Omit = omit, + timeframe_end: Union[str, datetime] | Omit = omit, + # 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](/api-reference/pagination). + + The event volume is aggregated by the hour and the + [timestamp](/api-reference/event/ingest-events) 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 ef92c9a3..0c2d31dc 100644 --- a/src/orb/resources/invoice_line_items.py +++ b/src/orb/resources/invoice_line_items.py @@ -2,35 +2,49 @@ from __future__ import annotations -from typing import Union +from typing import Union, Optional from datetime import date import httpx from .. import _legacy_response -from ..types import InvoiceLineItemCreateResponse, invoice_line_item_create_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import ( - maybe_transform, - async_maybe_transform, -) +from ..types import invoice_line_item_create_params +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +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 .._base_client import make_request_options +from ..types.invoice_line_item_create_response import InvoiceLineItemCreateResponse __all__ = ["InvoiceLineItems", "AsyncInvoiceLineItems"] class InvoiceLineItems(SyncAPIResource): + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + @cached_property def with_raw_response(self) -> InvoiceLineItemsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -39,15 +53,16 @@ def create( amount: str, end_date: Union[str, date], invoice_id: str, - name: str, quantity: float, start_date: Union[str, date], + item_id: Optional[str] | Omit = omit, + name: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> InvoiceLineItemCreateResponse: """This creates a one-off fixed fee invoice line item on an Invoice. @@ -55,6 +70,17 @@ def create( This can only be done for invoices that are in a `draft` status. + The behavior depends on which parameters are provided: + + - If `item_id` is provided without `name`: The item is looked up by ID, and the + item's name is used for the line item. + - If `name` is provided without `item_id`: An item with the given name is + searched for in the account. If found, that item is used. If not found, a new + item is created with that name. The new item's name is used for the line item. + - If both `item_id` and `name` are provided: The item is looked up by ID for + association, but the provided `name` is used for the line item (not the item's + name). + Args: amount: The total amount in the invoice's currency to add to the line item. @@ -62,13 +88,22 @@ def create( invoice_id: The id of the Invoice to add this line item. - name: The item name associated with this line item. If an item with the same name - exists in Orb, that item will be associated with the line item. - quantity: The number of units on the line item start_date: A date string to specify the line item's start date in the customer's timezone. + item_id: The id of the item to associate with this line item. If provided without `name`, + the item's name will be used for the price/line item. If provided with `name`, + the item will be associated but `name` will be used for the line item. At least + one of `name` or `item_id` must be provided. + + name: The name to use for the line item. If `item_id` is not provided, Orb will search + for an item with this name. If found, that item will be associated with the line + item. If not found, a new item will be created with this name. If `item_id` is + provided, this name will be used for the line item, but the item association + will be based on `item_id`. At least one of `name` or `item_id` must be + provided. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -86,9 +121,10 @@ def create( "amount": amount, "end_date": end_date, "invoice_id": invoice_id, - "name": name, "quantity": quantity, "start_date": start_date, + "item_id": item_id, + "name": name, }, invoice_line_item_create_params.InvoiceLineItemCreateParams, ), @@ -104,12 +140,30 @@ def create( class AsyncInvoiceLineItems(AsyncAPIResource): + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + @cached_property def with_raw_response(self) -> AsyncInvoiceLineItemsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -118,15 +172,16 @@ async def create( amount: str, end_date: Union[str, date], invoice_id: str, - name: str, quantity: float, start_date: Union[str, date], + item_id: Optional[str] | Omit = omit, + name: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> InvoiceLineItemCreateResponse: """This creates a one-off fixed fee invoice line item on an Invoice. @@ -134,6 +189,17 @@ async def create( This can only be done for invoices that are in a `draft` status. + The behavior depends on which parameters are provided: + + - If `item_id` is provided without `name`: The item is looked up by ID, and the + item's name is used for the line item. + - If `name` is provided without `item_id`: An item with the given name is + searched for in the account. If found, that item is used. If not found, a new + item is created with that name. The new item's name is used for the line item. + - If both `item_id` and `name` are provided: The item is looked up by ID for + association, but the provided `name` is used for the line item (not the item's + name). + Args: amount: The total amount in the invoice's currency to add to the line item. @@ -141,13 +207,22 @@ async def create( invoice_id: The id of the Invoice to add this line item. - name: The item name associated with this line item. If an item with the same name - exists in Orb, that item will be associated with the line item. - quantity: The number of units on the line item start_date: A date string to specify the line item's start date in the customer's timezone. + item_id: The id of the item to associate with this line item. If provided without `name`, + the item's name will be used for the price/line item. If provided with `name`, + the item will be associated but `name` will be used for the line item. At least + one of `name` or `item_id` must be provided. + + name: The name to use for the line item. If `item_id` is not provided, Orb will search + for an item with this name. If found, that item will be associated with the line + item. If not found, a new item will be created with this name. If `item_id` is + provided, this name will be used for the line item, but the item association + will be based on `item_id`. At least one of `name` or `item_id` must be + provided. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -165,9 +240,10 @@ async def create( "amount": amount, "end_date": end_date, "invoice_id": invoice_id, - "name": name, "quantity": quantity, "start_date": start_date, + "item_id": item_id, + "name": name, }, invoice_line_item_create_params.InvoiceLineItemCreateParams, ), diff --git a/src/orb/resources/invoices.py b/src/orb/resources/invoices.py index ea8b51ac..88c5e422 100644 --- a/src/orb/resources/invoices.py +++ b/src/orb/resources/invoices.py @@ -10,37 +10,57 @@ from .. import _legacy_response from ..types import ( - Invoice, - InvoiceFetchUpcomingResponse, + invoice_pay_params, invoice_list_params, + invoice_issue_params, invoice_create_params, + invoice_update_params, invoice_mark_paid_params, + invoice_list_summary_params, + invoice_issue_summary_params, invoice_fetch_upcoming_params, ) -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import ( - maybe_transform, - async_maybe_transform, -) +from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from .._utils import path_template, 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 ..pagination import SyncPage, AsyncPage -from .._base_client import ( - AsyncPaginator, - make_request_options, -) +from .._base_client import AsyncPaginator, make_request_options +from ..types.shared.invoice import Invoice +from ..types.shared_params.discount import Discount +from ..types.invoice_list_summary_response import InvoiceListSummaryResponse +from ..types.invoice_issue_summary_response import InvoiceIssueSummaryResponse +from ..types.invoice_fetch_upcoming_response import InvoiceFetchUpcomingResponse __all__ = ["Invoices", "AsyncInvoices"] class Invoices(SyncAPIResource): + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + @cached_property def with_raw_response(self) -> InvoicesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -49,18 +69,21 @@ def create( currency: str, invoice_date: Union[str, datetime], line_items: Iterable[invoice_create_params.LineItem], - net_terms: int, - customer_id: Optional[str] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - memo: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - will_auto_issue: bool | NotGiven = NOT_GIVEN, + auto_collection: Optional[bool] | Omit = omit, + customer_id: Optional[str] | Omit = omit, + discount: Optional[Discount] | Omit = omit, + due_date: Union[Union[str, date], Union[str, datetime], None] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + memo: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + net_terms: Optional[int] | Omit = omit, + will_auto_issue: bool | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Invoice: """ @@ -70,28 +93,41 @@ def create( currency: An ISO 4217 currency string. Must be the same as the customer's currency if it is set. - invoice_date: Optional invoice date to set. Must be in the past, if not set, `invoice_date` is - set to the current time in the customer's timezone. + invoice_date: An ISO 8601 date or timestamp, interpreted in the customer's timezone. Must be + in the past. If a date is set without a time, `invoice_date` is set to midnight + on the chosen date in the customer's timezone. - net_terms: 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 - 30 days to pay the invoice. + auto_collection: Determines whether this invoice will automatically attempt to charge a saved + payment method, if any. If not specified, the invoice inherits the customer's + auto_collection setting. customer_id: The id of the `Customer` to create this invoice for. One of `customer_id` and `external_customer_id` are required. + discount: An optional discount to attach to the invoice. + + due_date: An optional custom due date for the invoice. If not set, the due date will be + calculated based on the `net_terms` value. + external_customer_id: The `external_customer_id` of the `Customer` to create this invoice for. One of `customer_id` and `external_customer_id` are required. - memo: An optional memo to attach to the invoice. + memo: An optional memo to attach to the invoice. If no memo is provided, we will + attach the default memo 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`. - will_auto_issue: When true, this invoice will automatically be issued upon creation. When false, - the resulting invoice will require manual review to issue. Defaulted to false. + net_terms: The net terms determines the due date of the invoice. Due date is calculated + based on the invoice or issuance date, depending on the account's configured due + date calculation method. A value of '0' here represents that the invoice is due + on issue, whereas a value of '30' represents that the customer has 30 days to + pay the invoice. Do not set this field if you want to set a custom due date. + + will_auto_issue: When true, this invoice will be submitted for issuance upon creation. When + false, the resulting invoice will require manual review to issue. Defaulted to + false. extra_headers: Send extra headers @@ -110,11 +146,14 @@ def create( "currency": currency, "invoice_date": invoice_date, "line_items": line_items, - "net_terms": net_terms, + "auto_collection": auto_collection, "customer_id": customer_id, + "discount": discount, + "due_date": due_date, "external_customer_id": external_customer_id, "memo": memo, "metadata": metadata, + "net_terms": net_terms, "will_auto_issue": will_auto_issue, }, invoice_create_params.InvoiceCreateParams, @@ -129,50 +168,144 @@ def create( cast_to=Invoice, ) + def update( + self, + invoice_id: str, + *, + auto_collection: Optional[bool] | Omit = omit, + due_date: Union[Union[str, date], Union[str, datetime], None] | Omit = omit, + invoice_date: Union[Union[str, date], Union[str, datetime], None] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + net_terms: Optional[int] | Omit = omit, + # 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, + ) -> Invoice: + """ + This endpoint allows you to update the `metadata`, `net_terms`, `due_date`, + `invoice_date`, and `auto_collection` properties on an invoice. If you pass null + for the metadata value, it will clear any existing metadata for that invoice. + + `metadata` can be modified regardless of invoice state. `net_terms`, `due_date`, + `invoice_date`, and `auto_collection` can only be modified if the invoice is in + a `draft` state. `invoice_date` can only be modified for non-subscription + invoices. + + Args: + auto_collection: Determines whether this invoice will automatically attempt to charge a saved + payment method, if any. Can only be modified on draft invoices. If not + specified, the invoice's existing setting is unchanged. + + due_date: An optional custom due date for the invoice. If not set, the due date will be + calculated based on the `net_terms` value. + + invoice_date: The date of the invoice. Can only be modified for one-off draft invoices. + + 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`. + + net_terms: The net terms determines the due date of the invoice. Due date is calculated + based on the invoice or issuance date, depending on the account's configured due + date calculation method. A value of '0' here represents that the invoice is due + on issue, whereas a value of '30' represents that the customer has 30 days to + pay the invoice. Do not set this field if you want to set a custom due date. + + 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 invoice_id: + raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") + return self._put( + path_template("/invoices/{invoice_id}", invoice_id=invoice_id), + body=maybe_transform( + { + "auto_collection": auto_collection, + "due_date": due_date, + "invoice_date": invoice_date, + "metadata": metadata, + "net_terms": net_terms, + }, + invoice_update_params.InvoiceUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Invoice, + ) + def list( self, *, - amount: Optional[str] | NotGiven = NOT_GIVEN, - amount_gt: Optional[str] | NotGiven = NOT_GIVEN, - amount_lt: Optional[str] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - customer_id: Optional[str] | NotGiven = NOT_GIVEN, - date_type: Optional[Literal["due_date", "invoice_date"]] | NotGiven = NOT_GIVEN, - due_date: Union[str, date, None] | NotGiven = NOT_GIVEN, - due_date_window: Optional[str] | NotGiven = NOT_GIVEN, - due_date_gt: Union[str, date, None] | NotGiven = NOT_GIVEN, - due_date_lt: Union[str, date, None] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - invoice_date_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - invoice_date_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - invoice_date_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - invoice_date_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - is_recurring: Optional[bool] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - status: Optional[List[Literal["draft", "issued", "paid", "synced", "void"]]] | NotGiven = NOT_GIVEN, - subscription_id: Optional[str] | NotGiven = NOT_GIVEN, + amount: Optional[str] | Omit = omit, + amount_gt: Optional[str] | Omit = omit, + amount_lt: Optional[str] | Omit = omit, + cursor: Optional[str] | Omit = omit, + customer_id: Optional[str] | Omit = omit, + date_type: Optional[Literal["due_date", "invoice_date"]] | Omit = omit, + due_date: Union[str, date, None] | Omit = omit, + due_date_window: Optional[str] | Omit = omit, + due_date_gt: Union[str, date, None] | Omit = omit, + due_date_lt: Union[str, date, None] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + invoice_date_gt: Union[str, datetime, None] | Omit = omit, + invoice_date_gte: Union[str, datetime, None] | Omit = omit, + invoice_date_lt: Union[str, datetime, None] | Omit = omit, + invoice_date_lte: Union[str, datetime, None] | Omit = omit, + is_recurring: Optional[bool] | Omit = omit, + limit: int | Omit = omit, + status: Optional[List[Literal["draft", "issued", "paid", "synced", "void"]]] | Omit = omit, + subscription_id: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[Invoice]: """ - This endpoint returns a list of all [`Invoice`](../guides/concepts#invoice)s for - an account in a list format. + This endpoint returns a list of all [`Invoice`](/core-concepts#invoice)s for an + account in a list format. The list of invoices is ordered starting from the most recently issued invoice date. The response also includes - [`pagination_metadata`](../reference/pagination), which lets the caller retrieve - the next page of results if they exist. + [`pagination_metadata`](/api-reference/pagination), which lets the caller + retrieve the next page of results if they exist. 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. + + If you don't need line item details, minimums, maximums, or discounts, prefer + the [list invoices summary](/api-reference/invoice/list-invoices-summary) + endpoint for better performance. + Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned from the initial request. + due_date_window: Filters invoices by their due dates within a specific time range in the past. + Specify the range as a number followed by 'd' (days) or 'm' (months). For + example, '7d' filters invoices due in the last 7 days, and '2m' filters those + due in the last 2 months. + limit: The number of items to fetch. Defaults to 20. extra_headers: Send extra headers @@ -219,6 +352,58 @@ def list( model=Invoice, ) + def delete_line_item( + self, + line_item_id: str, + *, + invoice_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> None: + """ + This endpoint deletes an invoice line item from a draft invoice. + + This endpoint only allows deletion of one-off line items (not subscription-based + line items). The invoice must be in a draft status for this operation to + succeed. + + Args: + 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 invoice_id: + raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") + if not line_item_id: + raise ValueError(f"Expected a non-empty value for `line_item_id` but received {line_item_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template( + "/invoices/{invoice_id}/invoice_line_items/{line_item_id}", + invoice_id=invoice_id, + line_item_id=line_item_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=NoneType, + ) + def fetch( self, invoice_id: str, @@ -228,11 +413,11 @@ def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Invoice: """ - This endpoint is used to fetch an [`Invoice`](../guides/concepts#invoice) given - an identifier. + This endpoint is used to fetch an [`Invoice`](/core-concepts#invoice) given an + identifier. Args: extra_headers: Send extra headers @@ -246,7 +431,7 @@ def fetch( if not invoice_id: raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") return self._get( - f"/invoices/{invoice_id}", + path_template("/invoices/{invoice_id}", invoice_id=invoice_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -256,17 +441,17 @@ 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, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InvoiceFetchUpcomingResponse: """ This endpoint can be used to fetch the upcoming - [invoice](../guides/concepts#invoice) for the current billing period given a + [invoice](/core-concepts#invoice) for the current billing period given a subscription. Args: @@ -296,24 +481,31 @@ def issue( self, invoice_id: str, *, + synchronous: bool | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Invoice: """This endpoint allows an eligible invoice to be issued manually. This is only - possible with invoices where status is `draft`, `will_auto_issue` is true, and + possible with invoices where status is `draft`, `will_auto_issue` is false, and an `eligible_to_issue_at` is a time in the past. Issuing an invoice could possibly trigger side effects, some of which could be customer-visible (e.g. sending emails, auto-collecting payment, syncing the invoice to external 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 + that have 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 @@ -327,7 +519,8 @@ def issue( if not invoice_id: raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") return self._post( - f"/invoices/{invoice_id}/issue", + path_template("/invoices/{invoice_id}/issue", invoice_id=invoice_id), + body=maybe_transform({"synchronous": synchronous}, invoice_issue_params.InvoiceIssueParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -338,25 +531,184 @@ def issue( cast_to=Invoice, ) + def issue_summary( + self, + invoice_id: str, + *, + synchronous: bool | Omit = omit, + # 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, + ) -> InvoiceIssueSummaryResponse: + """This endpoint allows an eligible invoice to be issued manually. + + This is only + possible with invoices where status is `draft`, `will_auto_issue` is false, and + an `eligible_to_issue_at` is a time in the past. Issuing an invoice could + possibly trigger side effects, some of which could be customer-visible (e.g. + sending emails, auto-collecting payment, syncing the invoice to external + providers, etc). + + This is a lighter-weight alternative to the issue invoice endpoint, returning an + invoice summary without any line item details. + + 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 + that have 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 + + 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 invoice_id: + raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") + return self._post( + path_template("/invoices/summary/{invoice_id}/issue", invoice_id=invoice_id), + body=maybe_transform({"synchronous": synchronous}, invoice_issue_summary_params.InvoiceIssueSummaryParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=InvoiceIssueSummaryResponse, + ) + + def list_summary( + self, + *, + amount: Optional[str] | Omit = omit, + amount_gt: Optional[str] | Omit = omit, + amount_lt: Optional[str] | Omit = omit, + cursor: Optional[str] | Omit = omit, + customer_id: Optional[str] | Omit = omit, + date_type: Optional[Literal["due_date", "invoice_date"]] | Omit = omit, + due_date: Union[str, date, None] | Omit = omit, + due_date_window: Optional[str] | Omit = omit, + due_date_gt: Union[str, date, None] | Omit = omit, + due_date_lt: Union[str, date, None] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + invoice_date_gt: Union[str, datetime, None] | Omit = omit, + invoice_date_gte: Union[str, datetime, None] | Omit = omit, + invoice_date_lt: Union[str, datetime, None] | Omit = omit, + invoice_date_lte: Union[str, datetime, None] | Omit = omit, + is_recurring: Optional[bool] | Omit = omit, + limit: int | Omit = omit, + status: Optional[Literal["draft", "issued", "paid", "synced", "void"]] | Omit = omit, + subscription_id: Optional[str] | Omit = omit, + # 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, + ) -> SyncPage[InvoiceListSummaryResponse]: + """ + This is a lighter-weight endpoint that returns a list of all + [`Invoice`](/core-concepts#invoice) summaries for an account in a list format. + + These invoice summaries do not include line item details, minimums, maximums, + and discounts, making this endpoint more efficient. + + The list of invoices is ordered starting from the most recently issued invoice + date. The response also includes + [`pagination_metadata`](/api-reference/pagination), which lets the caller + retrieve the next page of results if they exist. + + 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. + + due_date_window: Filters invoices by their due dates within a specific time range in the past. + Specify the range as a number followed by 'd' (days) or 'm' (months). For + example, '7d' filters invoices due in the last 7 days, and '2m' filters those + due in the last 2 months. + + limit: The number of items to fetch. Defaults to 20. + + 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_api_list( + "/invoices/summary", + page=SyncPage[InvoiceListSummaryResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "amount": amount, + "amount_gt": amount_gt, + "amount_lt": amount_lt, + "cursor": cursor, + "customer_id": customer_id, + "date_type": date_type, + "due_date": due_date, + "due_date_window": due_date_window, + "due_date_gt": due_date_gt, + "due_date_lt": due_date_lt, + "external_customer_id": external_customer_id, + "invoice_date_gt": invoice_date_gt, + "invoice_date_gte": invoice_date_gte, + "invoice_date_lt": invoice_date_lt, + "invoice_date_lte": invoice_date_lte, + "is_recurring": is_recurring, + "limit": limit, + "status": status, + "subscription_id": subscription_id, + }, + invoice_list_summary_params.InvoiceListSummaryParams, + ), + ), + model=InvoiceListSummaryResponse, + ) + def mark_paid( self, invoice_id: str, *, payment_received_date: Union[str, date], - external_id: Optional[str] | NotGiven = NOT_GIVEN, - notes: Optional[str] | NotGiven = NOT_GIVEN, + external_id: Optional[str] | Omit = omit, + notes: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Invoice: - """This endpoint allows an invoice's status to be set the `paid` status. + """This endpoint allows an invoice's status to be set to the `paid` status. - This can - only be done to invoices that are in the `issued` status. + This + can only be done to invoices that are in the `issued` or `synced` status. Args: payment_received_date: A date string to specify the date of the payment. @@ -378,7 +730,7 @@ def mark_paid( if not invoice_id: raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") return self._post( - f"/invoices/{invoice_id}/mark_paid", + path_template("/invoices/{invoice_id}/mark_paid", invoice_id=invoice_id), body=maybe_transform( { "payment_received_date": payment_received_date, @@ -397,6 +749,56 @@ def mark_paid( cast_to=Invoice, ) + def pay( + self, + invoice_id: str, + *, + shared_payment_token_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> Invoice: + """This endpoint collects payment for an invoice. + + By default, it uses the + customer's default payment method. Optionally, a shared payment token (SPT) can + be provided to pay using agent-granted credentials instead. This action can only + be taken on invoices with status "issued". + + Args: + shared_payment_token_id: The ID of a shared payment token granted by an agent to use for this payment. + + 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 invoice_id: + raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") + return self._post( + path_template("/invoices/{invoice_id}/pay", invoice_id=invoice_id), + body=maybe_transform( + {"shared_payment_token_id": shared_payment_token_id}, invoice_pay_params.InvoicePayParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Invoice, + ) + def void( self, invoice_id: str, @@ -406,19 +808,23 @@ def void( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Invoice: - """This endpoint allows an invoice's status to be set the `void` status. + """This endpoint allows an invoice's status to be set to the `void` status. - This can - only be done to invoices that are in the `issued` status. + This + can only be done to invoices that are in the `issued` status. If the associated invoice has used the customer balance to change the amount due, the customer balance operation will be reverted. For example, if the - invoice used $10 of customer balance, that amount will be added back to the + invoice used \\$$10 of customer balance, that amount will be added back to the customer balance upon voiding. + If the invoice was used to purchase a credit block, but the invoice is not yet + paid, the credit block will be voided. If the invoice was created due to a + top-up, the top-up will be disabled. + Args: extra_headers: Send extra headers @@ -433,7 +839,140 @@ def void( if not invoice_id: raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") return self._post( - f"/invoices/{invoice_id}/void", + path_template("/invoices/{invoice_id}/void", invoice_id=invoice_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Invoice, + ) + + +class AsyncInvoices(AsyncAPIResource): + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + + @cached_property + def with_raw_response(self) -> AsyncInvoicesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( + self, + *, + currency: str, + invoice_date: Union[str, datetime], + line_items: Iterable[invoice_create_params.LineItem], + auto_collection: Optional[bool] | Omit = omit, + customer_id: Optional[str] | Omit = omit, + discount: Optional[Discount] | Omit = omit, + due_date: Union[Union[str, date], Union[str, datetime], None] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + memo: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + net_terms: Optional[int] | Omit = omit, + will_auto_issue: bool | Omit = omit, + # 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, + ) -> Invoice: + """ + This endpoint is used to create a one-off invoice for a customer. + + Args: + currency: An ISO 4217 currency string. Must be the same as the customer's currency if it + is set. + + invoice_date: An ISO 8601 date or timestamp, interpreted in the customer's timezone. Must be + in the past. If a date is set without a time, `invoice_date` is set to midnight + on the chosen date in the customer's timezone. + + auto_collection: Determines whether this invoice will automatically attempt to charge a saved + payment method, if any. If not specified, the invoice inherits the customer's + auto_collection setting. + + customer_id: The id of the `Customer` to create this invoice for. One of `customer_id` and + `external_customer_id` are required. + + discount: An optional discount to attach to the invoice. + + due_date: An optional custom due date for the invoice. If not set, the due date will be + calculated based on the `net_terms` value. + + external_customer_id: The `external_customer_id` of the `Customer` to create this invoice for. One of + `customer_id` and `external_customer_id` are required. + + memo: An optional memo to attach to the invoice. If no memo is provided, we will + attach the default memo + + 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`. + + net_terms: The net terms determines the due date of the invoice. Due date is calculated + based on the invoice or issuance date, depending on the account's configured due + date calculation method. A value of '0' here represents that the invoice is due + on issue, whereas a value of '30' represents that the customer has 30 days to + pay the invoice. Do not set this field if you want to set a custom due date. + + will_auto_issue: When true, this invoice will be submitted for issuance upon creation. When + false, the resulting invoice will require manual review to issue. Defaulted to + false. + + 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( + "/invoices", + body=await async_maybe_transform( + { + "currency": currency, + "invoice_date": invoice_date, + "line_items": line_items, + "auto_collection": auto_collection, + "customer_id": customer_id, + "discount": discount, + "due_date": due_date, + "external_customer_id": external_customer_id, + "memo": memo, + "metadata": metadata, + "net_terms": net_terms, + "will_auto_issue": will_auto_issue, + }, + invoice_create_params.InvoiceCreateParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -444,65 +983,52 @@ def void( cast_to=Invoice, ) - -class AsyncInvoices(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncInvoicesWithRawResponse: - return AsyncInvoicesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncInvoicesWithStreamingResponse: - return AsyncInvoicesWithStreamingResponse(self) - - async def create( + async def update( self, + invoice_id: str, *, - currency: str, - invoice_date: Union[str, datetime], - line_items: Iterable[invoice_create_params.LineItem], - net_terms: int, - customer_id: Optional[str] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - memo: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - will_auto_issue: bool | NotGiven = NOT_GIVEN, + auto_collection: Optional[bool] | Omit = omit, + due_date: Union[Union[str, date], Union[str, datetime], None] | Omit = omit, + invoice_date: Union[Union[str, date], Union[str, datetime], None] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + net_terms: Optional[int] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Invoice: """ - This endpoint is used to create a one-off invoice for a customer. - - Args: - currency: An ISO 4217 currency string. Must be the same as the customer's currency if it - is set. - - invoice_date: Optional invoice date to set. Must be in the past, if not set, `invoice_date` is - set to the current time in the customer's timezone. + This endpoint allows you to update the `metadata`, `net_terms`, `due_date`, + `invoice_date`, and `auto_collection` properties on an invoice. If you pass null + for the metadata value, it will clear any existing metadata for that invoice. - net_terms: 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 - 30 days to pay the invoice. + `metadata` can be modified regardless of invoice state. `net_terms`, `due_date`, + `invoice_date`, and `auto_collection` can only be modified if the invoice is in + a `draft` state. `invoice_date` can only be modified for non-subscription + invoices. - customer_id: The id of the `Customer` to create this invoice for. One of `customer_id` and - `external_customer_id` are required. + Args: + auto_collection: Determines whether this invoice will automatically attempt to charge a saved + payment method, if any. Can only be modified on draft invoices. If not + specified, the invoice's existing setting is unchanged. - external_customer_id: The `external_customer_id` of the `Customer` to create this invoice for. One of - `customer_id` and `external_customer_id` are required. + due_date: An optional custom due date for the invoice. If not set, the due date will be + calculated based on the `net_terms` value. - memo: An optional memo to attach to the invoice. + invoice_date: The date of the invoice. Can only be modified for one-off draft invoices. 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`. - will_auto_issue: When true, this invoice will automatically be issued upon creation. When false, - the resulting invoice will require manual review to issue. Defaulted to false. + net_terms: The net terms determines the due date of the invoice. Due date is calculated + based on the invoice or issuance date, depending on the account's configured due + date calculation method. A value of '0' here represents that the invoice is due + on issue, whereas a value of '30' represents that the customer has 30 days to + pay the invoice. Do not set this field if you want to set a custom due date. extra_headers: Send extra headers @@ -514,21 +1040,19 @@ async def create( idempotency_key: Specify a custom idempotency key for this request """ - return await self._post( - "/invoices", + if not invoice_id: + raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") + return await self._put( + path_template("/invoices/{invoice_id}", invoice_id=invoice_id), body=await async_maybe_transform( { - "currency": currency, + "auto_collection": auto_collection, + "due_date": due_date, "invoice_date": invoice_date, - "line_items": line_items, - "net_terms": net_terms, - "customer_id": customer_id, - "external_customer_id": external_customer_id, - "memo": memo, "metadata": metadata, - "will_auto_issue": will_auto_issue, + "net_terms": net_terms, }, - invoice_create_params.InvoiceCreateParams, + invoice_update_params.InvoiceUpdateParams, ), options=make_request_options( extra_headers=extra_headers, @@ -543,47 +1067,60 @@ async def create( def list( self, *, - amount: Optional[str] | NotGiven = NOT_GIVEN, - amount_gt: Optional[str] | NotGiven = NOT_GIVEN, - amount_lt: Optional[str] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - customer_id: Optional[str] | NotGiven = NOT_GIVEN, - date_type: Optional[Literal["due_date", "invoice_date"]] | NotGiven = NOT_GIVEN, - due_date: Union[str, date, None] | NotGiven = NOT_GIVEN, - due_date_window: Optional[str] | NotGiven = NOT_GIVEN, - due_date_gt: Union[str, date, None] | NotGiven = NOT_GIVEN, - due_date_lt: Union[str, date, None] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - invoice_date_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - invoice_date_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - invoice_date_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - invoice_date_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - is_recurring: Optional[bool] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - status: Optional[List[Literal["draft", "issued", "paid", "synced", "void"]]] | NotGiven = NOT_GIVEN, - subscription_id: Optional[str] | NotGiven = NOT_GIVEN, + amount: Optional[str] | Omit = omit, + amount_gt: Optional[str] | Omit = omit, + amount_lt: Optional[str] | Omit = omit, + cursor: Optional[str] | Omit = omit, + customer_id: Optional[str] | Omit = omit, + date_type: Optional[Literal["due_date", "invoice_date"]] | Omit = omit, + due_date: Union[str, date, None] | Omit = omit, + due_date_window: Optional[str] | Omit = omit, + due_date_gt: Union[str, date, None] | Omit = omit, + due_date_lt: Union[str, date, None] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + invoice_date_gt: Union[str, datetime, None] | Omit = omit, + invoice_date_gte: Union[str, datetime, None] | Omit = omit, + invoice_date_lt: Union[str, datetime, None] | Omit = omit, + invoice_date_lte: Union[str, datetime, None] | Omit = omit, + is_recurring: Optional[bool] | Omit = omit, + limit: int | Omit = omit, + status: Optional[List[Literal["draft", "issued", "paid", "synced", "void"]]] | Omit = omit, + subscription_id: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Invoice, AsyncPage[Invoice]]: """ - This endpoint returns a list of all [`Invoice`](../guides/concepts#invoice)s for - an account in a list format. + This endpoint returns a list of all [`Invoice`](/core-concepts#invoice)s for an + account in a list format. The list of invoices is ordered starting from the most recently issued invoice date. The response also includes - [`pagination_metadata`](../reference/pagination), which lets the caller retrieve - the next page of results if they exist. + [`pagination_metadata`](/api-reference/pagination), which lets the caller + retrieve the next page of results if they exist. 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. + + If you don't need line item details, minimums, maximums, or discounts, prefer + the [list invoices summary](/api-reference/invoice/list-invoices-summary) + endpoint for better performance. + Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned from the initial request. + due_date_window: Filters invoices by their due dates within a specific time range in the past. + Specify the range as a number followed by 'd' (days) or 'm' (months). For + example, '7d' filters invoices due in the last 7 days, and '2m' filters those + due in the last 2 months. + limit: The number of items to fetch. Defaults to 20. extra_headers: Send extra headers @@ -630,6 +1167,58 @@ def list( model=Invoice, ) + async def delete_line_item( + self, + line_item_id: str, + *, + invoice_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> None: + """ + This endpoint deletes an invoice line item from a draft invoice. + + This endpoint only allows deletion of one-off line items (not subscription-based + line items). The invoice must be in a draft status for this operation to + succeed. + + Args: + 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 invoice_id: + raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") + if not line_item_id: + raise ValueError(f"Expected a non-empty value for `line_item_id` but received {line_item_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template( + "/invoices/{invoice_id}/invoice_line_items/{line_item_id}", + invoice_id=invoice_id, + line_item_id=line_item_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=NoneType, + ) + async def fetch( self, invoice_id: str, @@ -639,11 +1228,11 @@ async def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Invoice: """ - This endpoint is used to fetch an [`Invoice`](../guides/concepts#invoice) given - an identifier. + This endpoint is used to fetch an [`Invoice`](/core-concepts#invoice) given an + identifier. Args: extra_headers: Send extra headers @@ -657,7 +1246,7 @@ async def fetch( if not invoice_id: raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") return await self._get( - f"/invoices/{invoice_id}", + path_template("/invoices/{invoice_id}", invoice_id=invoice_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -667,17 +1256,17 @@ 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, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InvoiceFetchUpcomingResponse: """ This endpoint can be used to fetch the upcoming - [invoice](../guides/concepts#invoice) for the current billing period given a + [invoice](/core-concepts#invoice) for the current billing period given a subscription. Args: @@ -707,24 +1296,31 @@ async def issue( self, invoice_id: str, *, + synchronous: bool | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Invoice: """This endpoint allows an eligible invoice to be issued manually. This is only - possible with invoices where status is `draft`, `will_auto_issue` is true, and + possible with invoices where status is `draft`, `will_auto_issue` is false, and an `eligible_to_issue_at` is a time in the past. Issuing an invoice could possibly trigger side effects, some of which could be customer-visible (e.g. sending emails, auto-collecting payment, syncing the invoice to external 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 + that have 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 @@ -738,7 +1334,8 @@ async def issue( if not invoice_id: 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", + path_template("/invoices/{invoice_id}/issue", invoice_id=invoice_id), + body=await async_maybe_transform({"synchronous": synchronous}, invoice_issue_params.InvoiceIssueParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -749,25 +1346,186 @@ async def issue( cast_to=Invoice, ) + async def issue_summary( + self, + invoice_id: str, + *, + synchronous: bool | Omit = omit, + # 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, + ) -> InvoiceIssueSummaryResponse: + """This endpoint allows an eligible invoice to be issued manually. + + This is only + possible with invoices where status is `draft`, `will_auto_issue` is false, and + an `eligible_to_issue_at` is a time in the past. Issuing an invoice could + possibly trigger side effects, some of which could be customer-visible (e.g. + sending emails, auto-collecting payment, syncing the invoice to external + providers, etc). + + This is a lighter-weight alternative to the issue invoice endpoint, returning an + invoice summary without any line item details. + + 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 + that have 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 + + 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 invoice_id: + raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") + return await self._post( + path_template("/invoices/summary/{invoice_id}/issue", invoice_id=invoice_id), + body=await async_maybe_transform( + {"synchronous": synchronous}, invoice_issue_summary_params.InvoiceIssueSummaryParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=InvoiceIssueSummaryResponse, + ) + + def list_summary( + self, + *, + amount: Optional[str] | Omit = omit, + amount_gt: Optional[str] | Omit = omit, + amount_lt: Optional[str] | Omit = omit, + cursor: Optional[str] | Omit = omit, + customer_id: Optional[str] | Omit = omit, + date_type: Optional[Literal["due_date", "invoice_date"]] | Omit = omit, + due_date: Union[str, date, None] | Omit = omit, + due_date_window: Optional[str] | Omit = omit, + due_date_gt: Union[str, date, None] | Omit = omit, + due_date_lt: Union[str, date, None] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + invoice_date_gt: Union[str, datetime, None] | Omit = omit, + invoice_date_gte: Union[str, datetime, None] | Omit = omit, + invoice_date_lt: Union[str, datetime, None] | Omit = omit, + invoice_date_lte: Union[str, datetime, None] | Omit = omit, + is_recurring: Optional[bool] | Omit = omit, + limit: int | Omit = omit, + status: Optional[Literal["draft", "issued", "paid", "synced", "void"]] | Omit = omit, + subscription_id: Optional[str] | Omit = omit, + # 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, + ) -> AsyncPaginator[InvoiceListSummaryResponse, AsyncPage[InvoiceListSummaryResponse]]: + """ + This is a lighter-weight endpoint that returns a list of all + [`Invoice`](/core-concepts#invoice) summaries for an account in a list format. + + These invoice summaries do not include line item details, minimums, maximums, + and discounts, making this endpoint more efficient. + + The list of invoices is ordered starting from the most recently issued invoice + date. The response also includes + [`pagination_metadata`](/api-reference/pagination), which lets the caller + retrieve the next page of results if they exist. + + 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. + + due_date_window: Filters invoices by their due dates within a specific time range in the past. + Specify the range as a number followed by 'd' (days) or 'm' (months). For + example, '7d' filters invoices due in the last 7 days, and '2m' filters those + due in the last 2 months. + + limit: The number of items to fetch. Defaults to 20. + + 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_api_list( + "/invoices/summary", + page=AsyncPage[InvoiceListSummaryResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "amount": amount, + "amount_gt": amount_gt, + "amount_lt": amount_lt, + "cursor": cursor, + "customer_id": customer_id, + "date_type": date_type, + "due_date": due_date, + "due_date_window": due_date_window, + "due_date_gt": due_date_gt, + "due_date_lt": due_date_lt, + "external_customer_id": external_customer_id, + "invoice_date_gt": invoice_date_gt, + "invoice_date_gte": invoice_date_gte, + "invoice_date_lt": invoice_date_lt, + "invoice_date_lte": invoice_date_lte, + "is_recurring": is_recurring, + "limit": limit, + "status": status, + "subscription_id": subscription_id, + }, + invoice_list_summary_params.InvoiceListSummaryParams, + ), + ), + model=InvoiceListSummaryResponse, + ) + async def mark_paid( self, invoice_id: str, *, payment_received_date: Union[str, date], - external_id: Optional[str] | NotGiven = NOT_GIVEN, - notes: Optional[str] | NotGiven = NOT_GIVEN, + external_id: Optional[str] | Omit = omit, + notes: Optional[str] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Invoice: - """This endpoint allows an invoice's status to be set the `paid` status. + """This endpoint allows an invoice's status to be set to the `paid` status. - This can - only be done to invoices that are in the `issued` status. + This + can only be done to invoices that are in the `issued` or `synced` status. Args: payment_received_date: A date string to specify the date of the payment. @@ -789,7 +1547,7 @@ async def mark_paid( if not invoice_id: raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") return await self._post( - f"/invoices/{invoice_id}/mark_paid", + path_template("/invoices/{invoice_id}/mark_paid", invoice_id=invoice_id), body=await async_maybe_transform( { "payment_received_date": payment_received_date, @@ -808,6 +1566,56 @@ async def mark_paid( cast_to=Invoice, ) + async def pay( + self, + invoice_id: str, + *, + shared_payment_token_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> Invoice: + """This endpoint collects payment for an invoice. + + By default, it uses the + customer's default payment method. Optionally, a shared payment token (SPT) can + be provided to pay using agent-granted credentials instead. This action can only + be taken on invoices with status "issued". + + Args: + shared_payment_token_id: The ID of a shared payment token granted by an agent to use for this payment. + + 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 invoice_id: + raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") + return await self._post( + path_template("/invoices/{invoice_id}/pay", invoice_id=invoice_id), + body=await async_maybe_transform( + {"shared_payment_token_id": shared_payment_token_id}, invoice_pay_params.InvoicePayParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Invoice, + ) + async def void( self, invoice_id: str, @@ -817,19 +1625,23 @@ async def void( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Invoice: - """This endpoint allows an invoice's status to be set the `void` status. + """This endpoint allows an invoice's status to be set to the `void` status. - This can - only be done to invoices that are in the `issued` status. + This + can only be done to invoices that are in the `issued` status. If the associated invoice has used the customer balance to change the amount due, the customer balance operation will be reverted. For example, if the - invoice used $10 of customer balance, that amount will be added back to the + invoice used \\$$10 of customer balance, that amount will be added back to the customer balance upon voiding. + If the invoice was used to purchase a credit block, but the invoice is not yet + paid, the credit block will be voided. If the invoice was created due to a + top-up, the top-up will be disabled. + Args: extra_headers: Send extra headers @@ -844,7 +1656,7 @@ async def void( if not invoice_id: raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") return await self._post( - f"/invoices/{invoice_id}/void", + path_template("/invoices/{invoice_id}/void", invoice_id=invoice_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -863,9 +1675,15 @@ def __init__(self, invoices: Invoices) -> None: self.create = _legacy_response.to_raw_response_wrapper( invoices.create, ) + self.update = _legacy_response.to_raw_response_wrapper( + invoices.update, + ) self.list = _legacy_response.to_raw_response_wrapper( invoices.list, ) + self.delete_line_item = _legacy_response.to_raw_response_wrapper( + invoices.delete_line_item, + ) self.fetch = _legacy_response.to_raw_response_wrapper( invoices.fetch, ) @@ -875,9 +1693,18 @@ def __init__(self, invoices: Invoices) -> None: self.issue = _legacy_response.to_raw_response_wrapper( invoices.issue, ) + self.issue_summary = _legacy_response.to_raw_response_wrapper( + invoices.issue_summary, + ) + self.list_summary = _legacy_response.to_raw_response_wrapper( + invoices.list_summary, + ) self.mark_paid = _legacy_response.to_raw_response_wrapper( invoices.mark_paid, ) + self.pay = _legacy_response.to_raw_response_wrapper( + invoices.pay, + ) self.void = _legacy_response.to_raw_response_wrapper( invoices.void, ) @@ -890,9 +1717,15 @@ def __init__(self, invoices: AsyncInvoices) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( invoices.create, ) + self.update = _legacy_response.async_to_raw_response_wrapper( + invoices.update, + ) self.list = _legacy_response.async_to_raw_response_wrapper( invoices.list, ) + self.delete_line_item = _legacy_response.async_to_raw_response_wrapper( + invoices.delete_line_item, + ) self.fetch = _legacy_response.async_to_raw_response_wrapper( invoices.fetch, ) @@ -902,9 +1735,18 @@ def __init__(self, invoices: AsyncInvoices) -> None: self.issue = _legacy_response.async_to_raw_response_wrapper( invoices.issue, ) + self.issue_summary = _legacy_response.async_to_raw_response_wrapper( + invoices.issue_summary, + ) + self.list_summary = _legacy_response.async_to_raw_response_wrapper( + invoices.list_summary, + ) self.mark_paid = _legacy_response.async_to_raw_response_wrapper( invoices.mark_paid, ) + self.pay = _legacy_response.async_to_raw_response_wrapper( + invoices.pay, + ) self.void = _legacy_response.async_to_raw_response_wrapper( invoices.void, ) @@ -917,9 +1759,15 @@ def __init__(self, invoices: Invoices) -> None: self.create = to_streamed_response_wrapper( invoices.create, ) + self.update = to_streamed_response_wrapper( + invoices.update, + ) self.list = to_streamed_response_wrapper( invoices.list, ) + self.delete_line_item = to_streamed_response_wrapper( + invoices.delete_line_item, + ) self.fetch = to_streamed_response_wrapper( invoices.fetch, ) @@ -929,9 +1777,18 @@ def __init__(self, invoices: Invoices) -> None: self.issue = to_streamed_response_wrapper( invoices.issue, ) + self.issue_summary = to_streamed_response_wrapper( + invoices.issue_summary, + ) + self.list_summary = to_streamed_response_wrapper( + invoices.list_summary, + ) self.mark_paid = to_streamed_response_wrapper( invoices.mark_paid, ) + self.pay = to_streamed_response_wrapper( + invoices.pay, + ) self.void = to_streamed_response_wrapper( invoices.void, ) @@ -944,9 +1801,15 @@ def __init__(self, invoices: AsyncInvoices) -> None: self.create = async_to_streamed_response_wrapper( invoices.create, ) + self.update = async_to_streamed_response_wrapper( + invoices.update, + ) self.list = async_to_streamed_response_wrapper( invoices.list, ) + self.delete_line_item = async_to_streamed_response_wrapper( + invoices.delete_line_item, + ) self.fetch = async_to_streamed_response_wrapper( invoices.fetch, ) @@ -956,9 +1819,18 @@ def __init__(self, invoices: AsyncInvoices) -> None: self.issue = async_to_streamed_response_wrapper( invoices.issue, ) + self.issue_summary = async_to_streamed_response_wrapper( + invoices.issue_summary, + ) + self.list_summary = async_to_streamed_response_wrapper( + invoices.list_summary, + ) self.mark_paid = async_to_streamed_response_wrapper( invoices.mark_paid, ) + self.pay = async_to_streamed_response_wrapper( + invoices.pay, + ) self.void = async_to_streamed_response_wrapper( invoices.void, ) diff --git a/src/orb/resources/items.py b/src/orb/resources/items.py index 63cf236f..09589686 100644 --- a/src/orb/resources/items.py +++ b/src/orb/resources/items.py @@ -2,56 +2,73 @@ from __future__ import annotations -from typing import Optional +from typing import Dict, Iterable, Optional import httpx from .. import _legacy_response -from ..types import Item, item_list_params, item_create_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import ( - maybe_transform, - async_maybe_transform, -) +from ..types import item_list_params, item_create_params, item_update_params +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import path_template, 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 ..pagination import SyncPage, AsyncPage -from .._base_client import ( - AsyncPaginator, - make_request_options, -) +from ..types.item import Item +from .._base_client import AsyncPaginator, make_request_options __all__ = ["Items", "AsyncItems"] class Items(SyncAPIResource): + """The Item resource represents a sellable product or good. + + Items are associated with all line items, billable metrics, + and prices and are used for defining external sync behavior for invoices and tax calculation purposes. + """ + @cached_property def with_raw_response(self) -> ItemsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( self, *, name: str, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Item: """ - This endpoint is used to create an [Item](../guides/concepts#item). + This endpoint is used to create an [Item](/core-concepts#item). Args: name: The name of the item. + 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 @@ -64,7 +81,68 @@ def create( """ return self._post( "/items", - body=maybe_transform({"name": name}, item_create_params.ItemCreateParams), + body=maybe_transform( + { + "name": name, + "metadata": metadata, + }, + item_create_params.ItemCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Item, + ) + + def update( + self, + item_id: str, + *, + external_connections: Optional[Iterable[item_update_params.ExternalConnection]] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + name: Optional[str] | Omit = omit, + # 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, + ) -> Item: + """ + This endpoint can be used to update properties on the Item. + + Args: + 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 + """ + if not item_id: + raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") + return self._put( + path_template("/items/{item_id}", item_id=item_id), + body=maybe_transform( + { + "external_connections": external_connections, + "metadata": metadata, + "name": name, + }, + item_update_params.ItemUpdateParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -78,14 +156,14 @@ def create( def list( self, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[Item]: """ This endpoint returns a list of all Items, ordered in descending order by @@ -124,6 +202,46 @@ def list( model=Item, ) + def archive( + self, + item_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> Item: + """ + Archive item + + Args: + 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 item_id: + raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") + return self._post( + path_template("/items/{item_id}/archive", item_id=item_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Item, + ) + def fetch( self, item_id: str, @@ -133,7 +251,7 @@ def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Item: """ This endpoint returns an item identified by its item_id. @@ -150,7 +268,7 @@ def fetch( if not item_id: raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") return self._get( - f"/items/{item_id}", + path_template("/items/{item_id}", item_id=item_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -159,32 +277,54 @@ def fetch( class AsyncItems(AsyncAPIResource): + """The Item resource represents a sellable product or good. + + Items are associated with all line items, billable metrics, + and prices and are used for defining external sync behavior for invoices and tax calculation purposes. + """ + @cached_property def with_raw_response(self) -> AsyncItemsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( self, *, name: str, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Item: """ - This endpoint is used to create an [Item](../guides/concepts#item). + This endpoint is used to create an [Item](/core-concepts#item). Args: name: The name of the item. + 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 @@ -197,7 +337,68 @@ async def create( """ return await self._post( "/items", - body=await async_maybe_transform({"name": name}, item_create_params.ItemCreateParams), + body=await async_maybe_transform( + { + "name": name, + "metadata": metadata, + }, + item_create_params.ItemCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Item, + ) + + async def update( + self, + item_id: str, + *, + external_connections: Optional[Iterable[item_update_params.ExternalConnection]] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + name: Optional[str] | Omit = omit, + # 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, + ) -> Item: + """ + This endpoint can be used to update properties on the Item. + + Args: + 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 + """ + if not item_id: + raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") + return await self._put( + path_template("/items/{item_id}", item_id=item_id), + body=await async_maybe_transform( + { + "external_connections": external_connections, + "metadata": metadata, + "name": name, + }, + item_update_params.ItemUpdateParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -211,14 +412,14 @@ async def create( def list( self, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Item, AsyncPage[Item]]: """ This endpoint returns a list of all Items, ordered in descending order by @@ -257,6 +458,46 @@ def list( model=Item, ) + async def archive( + self, + item_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> Item: + """ + Archive item + + Args: + 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 item_id: + raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") + return await self._post( + path_template("/items/{item_id}/archive", item_id=item_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Item, + ) + async def fetch( self, item_id: str, @@ -266,7 +507,7 @@ async def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Item: """ This endpoint returns an item identified by its item_id. @@ -283,7 +524,7 @@ async def fetch( if not item_id: raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") return await self._get( - f"/items/{item_id}", + path_template("/items/{item_id}", item_id=item_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -298,9 +539,15 @@ def __init__(self, items: Items) -> None: self.create = _legacy_response.to_raw_response_wrapper( items.create, ) + self.update = _legacy_response.to_raw_response_wrapper( + items.update, + ) self.list = _legacy_response.to_raw_response_wrapper( items.list, ) + self.archive = _legacy_response.to_raw_response_wrapper( + items.archive, + ) self.fetch = _legacy_response.to_raw_response_wrapper( items.fetch, ) @@ -313,9 +560,15 @@ def __init__(self, items: AsyncItems) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( items.create, ) + self.update = _legacy_response.async_to_raw_response_wrapper( + items.update, + ) self.list = _legacy_response.async_to_raw_response_wrapper( items.list, ) + self.archive = _legacy_response.async_to_raw_response_wrapper( + items.archive, + ) self.fetch = _legacy_response.async_to_raw_response_wrapper( items.fetch, ) @@ -328,9 +581,15 @@ def __init__(self, items: Items) -> None: self.create = to_streamed_response_wrapper( items.create, ) + self.update = to_streamed_response_wrapper( + items.update, + ) self.list = to_streamed_response_wrapper( items.list, ) + self.archive = to_streamed_response_wrapper( + items.archive, + ) self.fetch = to_streamed_response_wrapper( items.fetch, ) @@ -343,9 +602,15 @@ def __init__(self, items: AsyncItems) -> None: self.create = async_to_streamed_response_wrapper( items.create, ) + self.update = async_to_streamed_response_wrapper( + items.update, + ) self.list = async_to_streamed_response_wrapper( items.list, ) + self.archive = async_to_streamed_response_wrapper( + items.archive, + ) self.fetch = async_to_streamed_response_wrapper( items.fetch, ) diff --git a/src/orb/resources/license_types.py b/src/orb/resources/license_types.py new file mode 100644 index 00000000..f95b8e07 --- /dev/null +++ b/src/orb/resources/license_types.py @@ -0,0 +1,422 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from .. import _legacy_response +from ..types import license_type_list_params, license_type_create_params +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import path_template, 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 ..pagination import SyncPage, AsyncPage +from .._base_client import AsyncPaginator, make_request_options +from ..types.license_type_list_response import LicenseTypeListResponse +from ..types.license_type_create_response import LicenseTypeCreateResponse +from ..types.license_type_retrieve_response import LicenseTypeRetrieveResponse + +__all__ = ["LicenseTypes", "AsyncLicenseTypes"] + + +class LicenseTypes(SyncAPIResource): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + @cached_property + def with_raw_response(self) -> LicenseTypesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 LicenseTypesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> LicenseTypesWithStreamingResponse: + """ + 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 LicenseTypesWithStreamingResponse(self) + + def create( + self, + *, + grouping_key: str, + name: 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> LicenseTypeCreateResponse: + """ + This endpoint is used to create a new license type. + + License types are used to group licenses and define billing behavior. Each + license type has a name and a grouping key that determines how metrics are + aggregated for billing purposes. + + Args: + grouping_key: The key used for grouping licenses of this type. This is typically a user + identifier field. + + name: The name of the license type. + + 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( + "/license_types", + body=maybe_transform( + { + "grouping_key": grouping_key, + "name": name, + }, + license_type_create_params.LicenseTypeCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=LicenseTypeCreateResponse, + ) + + def retrieve( + self, + license_type_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LicenseTypeRetrieveResponse: + """ + This endpoint returns a license type identified by its license_type_id. + + Use this endpoint to retrieve details about a specific license type, including + its name and grouping key. + + Args: + 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 + """ + if not license_type_id: + raise ValueError(f"Expected a non-empty value for `license_type_id` but received {license_type_id!r}") + return self._get( + path_template("/license_types/{license_type_id}", license_type_id=license_type_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LicenseTypeRetrieveResponse, + ) + + def list( + self, + *, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + # 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, + ) -> SyncPage[LicenseTypeListResponse]: + """ + This endpoint returns a list of all license types configured for the account, + ordered in ascending order by creation time. + + License types are used to group licenses and define billing behavior. Each + license type has a name and a grouping key that determines how metrics are + aggregated for billing purposes. + + Args: + 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. + + 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_api_list( + "/license_types", + page=SyncPage[LicenseTypeListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "cursor": cursor, + "limit": limit, + }, + license_type_list_params.LicenseTypeListParams, + ), + ), + model=LicenseTypeListResponse, + ) + + +class AsyncLicenseTypes(AsyncAPIResource): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + @cached_property + def with_raw_response(self) -> AsyncLicenseTypesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncLicenseTypesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncLicenseTypesWithStreamingResponse: + """ + 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 AsyncLicenseTypesWithStreamingResponse(self) + + async def create( + self, + *, + grouping_key: str, + name: 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> LicenseTypeCreateResponse: + """ + This endpoint is used to create a new license type. + + License types are used to group licenses and define billing behavior. Each + license type has a name and a grouping key that determines how metrics are + aggregated for billing purposes. + + Args: + grouping_key: The key used for grouping licenses of this type. This is typically a user + identifier field. + + name: The name of the license type. + + 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( + "/license_types", + body=await async_maybe_transform( + { + "grouping_key": grouping_key, + "name": name, + }, + license_type_create_params.LicenseTypeCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=LicenseTypeCreateResponse, + ) + + async def retrieve( + self, + license_type_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LicenseTypeRetrieveResponse: + """ + This endpoint returns a license type identified by its license_type_id. + + Use this endpoint to retrieve details about a specific license type, including + its name and grouping key. + + Args: + 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 + """ + if not license_type_id: + raise ValueError(f"Expected a non-empty value for `license_type_id` but received {license_type_id!r}") + return await self._get( + path_template("/license_types/{license_type_id}", license_type_id=license_type_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LicenseTypeRetrieveResponse, + ) + + def list( + self, + *, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + # 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, + ) -> AsyncPaginator[LicenseTypeListResponse, AsyncPage[LicenseTypeListResponse]]: + """ + This endpoint returns a list of all license types configured for the account, + ordered in ascending order by creation time. + + License types are used to group licenses and define billing behavior. Each + license type has a name and a grouping key that determines how metrics are + aggregated for billing purposes. + + Args: + 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. + + 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_api_list( + "/license_types", + page=AsyncPage[LicenseTypeListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "cursor": cursor, + "limit": limit, + }, + license_type_list_params.LicenseTypeListParams, + ), + ), + model=LicenseTypeListResponse, + ) + + +class LicenseTypesWithRawResponse: + def __init__(self, license_types: LicenseTypes) -> None: + self._license_types = license_types + + self.create = _legacy_response.to_raw_response_wrapper( + license_types.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + license_types.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + license_types.list, + ) + + +class AsyncLicenseTypesWithRawResponse: + def __init__(self, license_types: AsyncLicenseTypes) -> None: + self._license_types = license_types + + self.create = _legacy_response.async_to_raw_response_wrapper( + license_types.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + license_types.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + license_types.list, + ) + + +class LicenseTypesWithStreamingResponse: + def __init__(self, license_types: LicenseTypes) -> None: + self._license_types = license_types + + self.create = to_streamed_response_wrapper( + license_types.create, + ) + self.retrieve = to_streamed_response_wrapper( + license_types.retrieve, + ) + self.list = to_streamed_response_wrapper( + license_types.list, + ) + + +class AsyncLicenseTypesWithStreamingResponse: + def __init__(self, license_types: AsyncLicenseTypes) -> None: + self._license_types = license_types + + self.create = async_to_streamed_response_wrapper( + license_types.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + license_types.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + license_types.list, + ) diff --git a/src/orb/resources/licenses/__init__.py b/src/orb/resources/licenses/__init__.py new file mode 100644 index 00000000..0bc5c53e --- /dev/null +++ b/src/orb/resources/licenses/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .usage import ( + Usage, + AsyncUsage, + UsageWithRawResponse, + AsyncUsageWithRawResponse, + UsageWithStreamingResponse, + AsyncUsageWithStreamingResponse, +) +from .licenses import ( + Licenses, + AsyncLicenses, + LicensesWithRawResponse, + AsyncLicensesWithRawResponse, + LicensesWithStreamingResponse, + AsyncLicensesWithStreamingResponse, +) +from .external_licenses import ( + ExternalLicenses, + AsyncExternalLicenses, + ExternalLicensesWithRawResponse, + AsyncExternalLicensesWithRawResponse, + ExternalLicensesWithStreamingResponse, + AsyncExternalLicensesWithStreamingResponse, +) + +__all__ = [ + "ExternalLicenses", + "AsyncExternalLicenses", + "ExternalLicensesWithRawResponse", + "AsyncExternalLicensesWithRawResponse", + "ExternalLicensesWithStreamingResponse", + "AsyncExternalLicensesWithStreamingResponse", + "Usage", + "AsyncUsage", + "UsageWithRawResponse", + "AsyncUsageWithRawResponse", + "UsageWithStreamingResponse", + "AsyncUsageWithStreamingResponse", + "Licenses", + "AsyncLicenses", + "LicensesWithRawResponse", + "AsyncLicensesWithRawResponse", + "LicensesWithStreamingResponse", + "AsyncLicensesWithStreamingResponse", +] diff --git a/src/orb/resources/licenses/external_licenses.py b/src/orb/resources/licenses/external_licenses.py new file mode 100644 index 00000000..7b84aeb2 --- /dev/null +++ b/src/orb/resources/licenses/external_licenses.py @@ -0,0 +1,256 @@ +# 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 date + +import httpx + +from ... import _legacy_response +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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.licenses import external_license_get_usage_params +from ...types.licenses.external_license_get_usage_response import ExternalLicenseGetUsageResponse + +__all__ = ["ExternalLicenses", "AsyncExternalLicenses"] + + +class ExternalLicenses(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ExternalLicensesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 ExternalLicensesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ExternalLicensesWithStreamingResponse: + """ + 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 ExternalLicensesWithStreamingResponse(self) + + def get_usage( + self, + external_license_id: str, + *, + license_type_id: str, + subscription_id: str, + cursor: Optional[str] | Omit = omit, + end_date: Union[str, date, None] | Omit = omit, + group_by: Optional[str] | Omit = omit, + limit: int | Omit = omit, + start_date: Union[str, date, None] | Omit = omit, + # 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, + ) -> ExternalLicenseGetUsageResponse: + """ + Returns usage and remaining credits for a license identified by its external + license ID. + + Date range defaults to the current billing period if not specified. + + Args: + license_type_id: The license type ID to filter licenses by. + + subscription_id: The subscription ID to get license usage for. + + cursor: Pagination cursor from a previous request. + + end_date: End date for the usage period (YYYY-MM-DD). Defaults to end of current billing + period. + + group_by: How to group the results. Valid values: 'license', 'day'. Can be combined (e.g., + 'license,day'). + + limit: Maximum number of rows in the response data (default 20, max 100). + + start_date: Start date for the usage period (YYYY-MM-DD). Defaults to start of current + billing period. + + 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 + """ + if not external_license_id: + raise ValueError( + f"Expected a non-empty value for `external_license_id` but received {external_license_id!r}" + ) + return self._get( + path_template( + "/licenses/external_licenses/{external_license_id}/usage", external_license_id=external_license_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "license_type_id": license_type_id, + "subscription_id": subscription_id, + "cursor": cursor, + "end_date": end_date, + "group_by": group_by, + "limit": limit, + "start_date": start_date, + }, + external_license_get_usage_params.ExternalLicenseGetUsageParams, + ), + ), + cast_to=ExternalLicenseGetUsageResponse, + ) + + +class AsyncExternalLicenses(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncExternalLicensesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncExternalLicensesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncExternalLicensesWithStreamingResponse: + """ + 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 AsyncExternalLicensesWithStreamingResponse(self) + + async def get_usage( + self, + external_license_id: str, + *, + license_type_id: str, + subscription_id: str, + cursor: Optional[str] | Omit = omit, + end_date: Union[str, date, None] | Omit = omit, + group_by: Optional[str] | Omit = omit, + limit: int | Omit = omit, + start_date: Union[str, date, None] | Omit = omit, + # 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, + ) -> ExternalLicenseGetUsageResponse: + """ + Returns usage and remaining credits for a license identified by its external + license ID. + + Date range defaults to the current billing period if not specified. + + Args: + license_type_id: The license type ID to filter licenses by. + + subscription_id: The subscription ID to get license usage for. + + cursor: Pagination cursor from a previous request. + + end_date: End date for the usage period (YYYY-MM-DD). Defaults to end of current billing + period. + + group_by: How to group the results. Valid values: 'license', 'day'. Can be combined (e.g., + 'license,day'). + + limit: Maximum number of rows in the response data (default 20, max 100). + + start_date: Start date for the usage period (YYYY-MM-DD). Defaults to start of current + billing period. + + 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 + """ + if not external_license_id: + raise ValueError( + f"Expected a non-empty value for `external_license_id` but received {external_license_id!r}" + ) + return await self._get( + path_template( + "/licenses/external_licenses/{external_license_id}/usage", external_license_id=external_license_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "license_type_id": license_type_id, + "subscription_id": subscription_id, + "cursor": cursor, + "end_date": end_date, + "group_by": group_by, + "limit": limit, + "start_date": start_date, + }, + external_license_get_usage_params.ExternalLicenseGetUsageParams, + ), + ), + cast_to=ExternalLicenseGetUsageResponse, + ) + + +class ExternalLicensesWithRawResponse: + def __init__(self, external_licenses: ExternalLicenses) -> None: + self._external_licenses = external_licenses + + self.get_usage = _legacy_response.to_raw_response_wrapper( + external_licenses.get_usage, + ) + + +class AsyncExternalLicensesWithRawResponse: + def __init__(self, external_licenses: AsyncExternalLicenses) -> None: + self._external_licenses = external_licenses + + self.get_usage = _legacy_response.async_to_raw_response_wrapper( + external_licenses.get_usage, + ) + + +class ExternalLicensesWithStreamingResponse: + def __init__(self, external_licenses: ExternalLicenses) -> None: + self._external_licenses = external_licenses + + self.get_usage = to_streamed_response_wrapper( + external_licenses.get_usage, + ) + + +class AsyncExternalLicensesWithStreamingResponse: + def __init__(self, external_licenses: AsyncExternalLicenses) -> None: + self._external_licenses = external_licenses + + self.get_usage = async_to_streamed_response_wrapper( + external_licenses.get_usage, + ) diff --git a/src/orb/resources/licenses/licenses.py b/src/orb/resources/licenses/licenses.py new file mode 100644 index 00000000..ea56b1c4 --- /dev/null +++ b/src/orb/resources/licenses/licenses.py @@ -0,0 +1,731 @@ +# 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 date +from typing_extensions import Literal + +import httpx + +from ... import _legacy_response +from .usage import ( + Usage, + AsyncUsage, + UsageWithRawResponse, + AsyncUsageWithRawResponse, + UsageWithStreamingResponse, + AsyncUsageWithStreamingResponse, +) +from ...types import ( + license_list_params, + license_create_params, + license_deactivate_params, + license_retrieve_by_external_id_params, +) +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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 ...pagination import SyncPage, AsyncPage +from ..._base_client import AsyncPaginator, make_request_options +from .external_licenses import ( + ExternalLicenses, + AsyncExternalLicenses, + ExternalLicensesWithRawResponse, + AsyncExternalLicensesWithRawResponse, + ExternalLicensesWithStreamingResponse, + AsyncExternalLicensesWithStreamingResponse, +) +from ...types.license_list_response import LicenseListResponse +from ...types.license_create_response import LicenseCreateResponse +from ...types.license_retrieve_response import LicenseRetrieveResponse +from ...types.license_deactivate_response import LicenseDeactivateResponse +from ...types.license_retrieve_by_external_id_response import LicenseRetrieveByExternalIDResponse + +__all__ = ["Licenses", "AsyncLicenses"] + + +class Licenses(SyncAPIResource): + @cached_property + def external_licenses(self) -> ExternalLicenses: + return ExternalLicenses(self._client) + + @cached_property + def usage(self) -> Usage: + return Usage(self._client) + + @cached_property + def with_raw_response(self) -> LicensesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 LicensesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> LicensesWithStreamingResponse: + """ + 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 LicensesWithStreamingResponse(self) + + def create( + self, + *, + external_license_id: str, + license_type_id: str, + subscription_id: str, + end_date: Union[str, date, None] | Omit = omit, + start_date: Union[str, date, None] | Omit = omit, + # 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, + ) -> LicenseCreateResponse: + """ + This endpoint is used to create a new license for a user. + + If a start date is provided, the license will be activated at the **start** of + the specified date in the customer's timezone. Otherwise, the activation time + will default to the **start** of the current day in the customer's timezone. + + Args: + external_license_id: The external identifier for the license. + + end_date: The end date of the license. If not provided, the license will remain active + until deactivated. + + start_date: The start date of the license. If not provided, defaults to start of day today + in the customer's timezone. + + 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( + "/licenses", + body=maybe_transform( + { + "external_license_id": external_license_id, + "license_type_id": license_type_id, + "subscription_id": subscription_id, + "end_date": end_date, + "start_date": start_date, + }, + license_create_params.LicenseCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=LicenseCreateResponse, + ) + + def retrieve( + self, + license_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LicenseRetrieveResponse: + """ + This endpoint is used to fetch a license given an identifier. + + Args: + 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 + """ + if not license_id: + raise ValueError(f"Expected a non-empty value for `license_id` but received {license_id!r}") + return self._get( + path_template("/licenses/{license_id}", license_id=license_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LicenseRetrieveResponse, + ) + + def list( + self, + *, + subscription_id: str, + cursor: Optional[str] | Omit = omit, + external_license_id: Optional[str] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + limit: int | Omit = omit, + status: Optional[Literal["active", "inactive"]] | Omit = omit, + # 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, + ) -> SyncPage[LicenseListResponse]: + """ + This endpoint returns a list of all licenses for a subscription. + + Args: + 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. + + 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_api_list( + "/licenses", + page=SyncPage[LicenseListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "subscription_id": subscription_id, + "cursor": cursor, + "external_license_id": external_license_id, + "license_type_id": license_type_id, + "limit": limit, + "status": status, + }, + license_list_params.LicenseListParams, + ), + ), + model=LicenseListResponse, + ) + + def deactivate( + self, + license_id: str, + *, + end_date: Union[str, date, None] | Omit = omit, + # 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, + ) -> LicenseDeactivateResponse: + """ + This endpoint is used to deactivate an existing license. + + If an end date is provided, the license will be deactivated at the **start** of + the specified date in the customer's timezone. Otherwise, the deactivation time + will default to the **end** of the current day in the customer's timezone. + + Args: + end_date: The date to deactivate the license. If not provided, defaults to end of day + today in the customer's timezone. + + 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 license_id: + raise ValueError(f"Expected a non-empty value for `license_id` but received {license_id!r}") + return self._post( + path_template("/licenses/{license_id}/deactivate", license_id=license_id), + body=maybe_transform({"end_date": end_date}, license_deactivate_params.LicenseDeactivateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=LicenseDeactivateResponse, + ) + + def retrieve_by_external_id( + self, + external_license_id: str, + *, + license_type_id: str, + 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LicenseRetrieveByExternalIDResponse: + """ + This endpoint is used to fetch a license given an external license identifier. + + Args: + license_type_id: The ID of the license type to fetch the license for. + + subscription_id: The ID of the subscription to fetch the license for. + + 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 + """ + if not external_license_id: + raise ValueError( + f"Expected a non-empty value for `external_license_id` but received {external_license_id!r}" + ) + return self._get( + path_template( + "/licenses/external_license_id/{external_license_id}", external_license_id=external_license_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "license_type_id": license_type_id, + "subscription_id": subscription_id, + }, + license_retrieve_by_external_id_params.LicenseRetrieveByExternalIDParams, + ), + ), + cast_to=LicenseRetrieveByExternalIDResponse, + ) + + +class AsyncLicenses(AsyncAPIResource): + @cached_property + def external_licenses(self) -> AsyncExternalLicenses: + return AsyncExternalLicenses(self._client) + + @cached_property + def usage(self) -> AsyncUsage: + return AsyncUsage(self._client) + + @cached_property + def with_raw_response(self) -> AsyncLicensesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncLicensesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncLicensesWithStreamingResponse: + """ + 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 AsyncLicensesWithStreamingResponse(self) + + async def create( + self, + *, + external_license_id: str, + license_type_id: str, + subscription_id: str, + end_date: Union[str, date, None] | Omit = omit, + start_date: Union[str, date, None] | Omit = omit, + # 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, + ) -> LicenseCreateResponse: + """ + This endpoint is used to create a new license for a user. + + If a start date is provided, the license will be activated at the **start** of + the specified date in the customer's timezone. Otherwise, the activation time + will default to the **start** of the current day in the customer's timezone. + + Args: + external_license_id: The external identifier for the license. + + end_date: The end date of the license. If not provided, the license will remain active + until deactivated. + + start_date: The start date of the license. If not provided, defaults to start of day today + in the customer's timezone. + + 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( + "/licenses", + body=await async_maybe_transform( + { + "external_license_id": external_license_id, + "license_type_id": license_type_id, + "subscription_id": subscription_id, + "end_date": end_date, + "start_date": start_date, + }, + license_create_params.LicenseCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=LicenseCreateResponse, + ) + + async def retrieve( + self, + license_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LicenseRetrieveResponse: + """ + This endpoint is used to fetch a license given an identifier. + + Args: + 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 + """ + if not license_id: + raise ValueError(f"Expected a non-empty value for `license_id` but received {license_id!r}") + return await self._get( + path_template("/licenses/{license_id}", license_id=license_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LicenseRetrieveResponse, + ) + + def list( + self, + *, + subscription_id: str, + cursor: Optional[str] | Omit = omit, + external_license_id: Optional[str] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + limit: int | Omit = omit, + status: Optional[Literal["active", "inactive"]] | Omit = omit, + # 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, + ) -> AsyncPaginator[LicenseListResponse, AsyncPage[LicenseListResponse]]: + """ + This endpoint returns a list of all licenses for a subscription. + + Args: + 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. + + 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_api_list( + "/licenses", + page=AsyncPage[LicenseListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "subscription_id": subscription_id, + "cursor": cursor, + "external_license_id": external_license_id, + "license_type_id": license_type_id, + "limit": limit, + "status": status, + }, + license_list_params.LicenseListParams, + ), + ), + model=LicenseListResponse, + ) + + async def deactivate( + self, + license_id: str, + *, + end_date: Union[str, date, None] | Omit = omit, + # 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, + ) -> LicenseDeactivateResponse: + """ + This endpoint is used to deactivate an existing license. + + If an end date is provided, the license will be deactivated at the **start** of + the specified date in the customer's timezone. Otherwise, the deactivation time + will default to the **end** of the current day in the customer's timezone. + + Args: + end_date: The date to deactivate the license. If not provided, defaults to end of day + today in the customer's timezone. + + 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 license_id: + raise ValueError(f"Expected a non-empty value for `license_id` but received {license_id!r}") + return await self._post( + path_template("/licenses/{license_id}/deactivate", license_id=license_id), + body=await async_maybe_transform({"end_date": end_date}, license_deactivate_params.LicenseDeactivateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=LicenseDeactivateResponse, + ) + + async def retrieve_by_external_id( + self, + external_license_id: str, + *, + license_type_id: str, + 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LicenseRetrieveByExternalIDResponse: + """ + This endpoint is used to fetch a license given an external license identifier. + + Args: + license_type_id: The ID of the license type to fetch the license for. + + subscription_id: The ID of the subscription to fetch the license for. + + 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 + """ + if not external_license_id: + raise ValueError( + f"Expected a non-empty value for `external_license_id` but received {external_license_id!r}" + ) + return await self._get( + path_template( + "/licenses/external_license_id/{external_license_id}", external_license_id=external_license_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "license_type_id": license_type_id, + "subscription_id": subscription_id, + }, + license_retrieve_by_external_id_params.LicenseRetrieveByExternalIDParams, + ), + ), + cast_to=LicenseRetrieveByExternalIDResponse, + ) + + +class LicensesWithRawResponse: + def __init__(self, licenses: Licenses) -> None: + self._licenses = licenses + + self.create = _legacy_response.to_raw_response_wrapper( + licenses.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + licenses.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + licenses.list, + ) + self.deactivate = _legacy_response.to_raw_response_wrapper( + licenses.deactivate, + ) + self.retrieve_by_external_id = _legacy_response.to_raw_response_wrapper( + licenses.retrieve_by_external_id, + ) + + @cached_property + def external_licenses(self) -> ExternalLicensesWithRawResponse: + return ExternalLicensesWithRawResponse(self._licenses.external_licenses) + + @cached_property + def usage(self) -> UsageWithRawResponse: + return UsageWithRawResponse(self._licenses.usage) + + +class AsyncLicensesWithRawResponse: + def __init__(self, licenses: AsyncLicenses) -> None: + self._licenses = licenses + + self.create = _legacy_response.async_to_raw_response_wrapper( + licenses.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + licenses.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + licenses.list, + ) + self.deactivate = _legacy_response.async_to_raw_response_wrapper( + licenses.deactivate, + ) + self.retrieve_by_external_id = _legacy_response.async_to_raw_response_wrapper( + licenses.retrieve_by_external_id, + ) + + @cached_property + def external_licenses(self) -> AsyncExternalLicensesWithRawResponse: + return AsyncExternalLicensesWithRawResponse(self._licenses.external_licenses) + + @cached_property + def usage(self) -> AsyncUsageWithRawResponse: + return AsyncUsageWithRawResponse(self._licenses.usage) + + +class LicensesWithStreamingResponse: + def __init__(self, licenses: Licenses) -> None: + self._licenses = licenses + + self.create = to_streamed_response_wrapper( + licenses.create, + ) + self.retrieve = to_streamed_response_wrapper( + licenses.retrieve, + ) + self.list = to_streamed_response_wrapper( + licenses.list, + ) + self.deactivate = to_streamed_response_wrapper( + licenses.deactivate, + ) + self.retrieve_by_external_id = to_streamed_response_wrapper( + licenses.retrieve_by_external_id, + ) + + @cached_property + def external_licenses(self) -> ExternalLicensesWithStreamingResponse: + return ExternalLicensesWithStreamingResponse(self._licenses.external_licenses) + + @cached_property + def usage(self) -> UsageWithStreamingResponse: + return UsageWithStreamingResponse(self._licenses.usage) + + +class AsyncLicensesWithStreamingResponse: + def __init__(self, licenses: AsyncLicenses) -> None: + self._licenses = licenses + + self.create = async_to_streamed_response_wrapper( + licenses.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + licenses.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + licenses.list, + ) + self.deactivate = async_to_streamed_response_wrapper( + licenses.deactivate, + ) + self.retrieve_by_external_id = async_to_streamed_response_wrapper( + licenses.retrieve_by_external_id, + ) + + @cached_property + def external_licenses(self) -> AsyncExternalLicensesWithStreamingResponse: + return AsyncExternalLicensesWithStreamingResponse(self._licenses.external_licenses) + + @cached_property + def usage(self) -> AsyncUsageWithStreamingResponse: + return AsyncUsageWithStreamingResponse(self._licenses.usage) diff --git a/src/orb/resources/licenses/usage.py b/src/orb/resources/licenses/usage.py new file mode 100644 index 00000000..ba9a551e --- /dev/null +++ b/src/orb/resources/licenses/usage.py @@ -0,0 +1,387 @@ +# 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 date + +import httpx + +from ... import _legacy_response +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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.licenses import usage_get_usage_params, usage_get_all_usage_params +from ...types.licenses.usage_get_usage_response import UsageGetUsageResponse +from ...types.licenses.usage_get_all_usage_response import UsageGetAllUsageResponse + +__all__ = ["Usage", "AsyncUsage"] + + +class Usage(SyncAPIResource): + @cached_property + def with_raw_response(self) -> UsageWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 UsageWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> UsageWithStreamingResponse: + """ + 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 UsageWithStreamingResponse(self) + + def get_all_usage( + self, + *, + license_type_id: str, + subscription_id: str, + cursor: Optional[str] | Omit = omit, + end_date: Union[str, date, None] | Omit = omit, + group_by: Optional[str] | Omit = omit, + limit: int | Omit = omit, + start_date: Union[str, date, None] | Omit = omit, + # 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, + ) -> UsageGetAllUsageResponse: + """ + Returns usage and remaining credits for all licenses of a given type on a + subscription. + + Date range defaults to the current billing period if not specified. + + Args: + license_type_id: The license type ID to filter licenses by. + + subscription_id: The subscription ID to get license usage for. + + cursor: Pagination cursor from a previous request. + + end_date: End date for the usage period (YYYY-MM-DD). Defaults to end of current billing + period. + + group_by: How to group the results. Valid values: 'license', 'day'. Can be combined (e.g., + 'license,day'). + + limit: Maximum number of rows in the response data (default 20, max 100). + + start_date: Start date for the usage period (YYYY-MM-DD). Defaults to start of current + billing period. + + 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( + "/licenses/usage", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "license_type_id": license_type_id, + "subscription_id": subscription_id, + "cursor": cursor, + "end_date": end_date, + "group_by": group_by, + "limit": limit, + "start_date": start_date, + }, + usage_get_all_usage_params.UsageGetAllUsageParams, + ), + ), + cast_to=UsageGetAllUsageResponse, + ) + + def get_usage( + self, + license_id: str, + *, + cursor: Optional[str] | Omit = omit, + end_date: Union[str, date, None] | Omit = omit, + group_by: Optional[str] | Omit = omit, + limit: int | Omit = omit, + start_date: Union[str, date, None] | Omit = omit, + # 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, + ) -> UsageGetUsageResponse: + """ + Returns usage and remaining credits for a specific license over a date range. + + Date range defaults to the current billing period if not specified. + + Args: + cursor: Pagination cursor from a previous request. + + end_date: End date for the usage period (YYYY-MM-DD). Defaults to end of current billing + period. + + group_by: How to group the results. Valid values: 'license', 'day'. Can be combined (e.g., + 'license,day'). + + limit: Maximum number of rows in the response data (default 20, max 100). + + start_date: Start date for the usage period (YYYY-MM-DD). Defaults to start of current + billing period. + + 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 + """ + if not license_id: + raise ValueError(f"Expected a non-empty value for `license_id` but received {license_id!r}") + return self._get( + path_template("/licenses/{license_id}/usage", license_id=license_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "cursor": cursor, + "end_date": end_date, + "group_by": group_by, + "limit": limit, + "start_date": start_date, + }, + usage_get_usage_params.UsageGetUsageParams, + ), + ), + cast_to=UsageGetUsageResponse, + ) + + +class AsyncUsage(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncUsageWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncUsageWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncUsageWithStreamingResponse: + """ + 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 AsyncUsageWithStreamingResponse(self) + + async def get_all_usage( + self, + *, + license_type_id: str, + subscription_id: str, + cursor: Optional[str] | Omit = omit, + end_date: Union[str, date, None] | Omit = omit, + group_by: Optional[str] | Omit = omit, + limit: int | Omit = omit, + start_date: Union[str, date, None] | Omit = omit, + # 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, + ) -> UsageGetAllUsageResponse: + """ + Returns usage and remaining credits for all licenses of a given type on a + subscription. + + Date range defaults to the current billing period if not specified. + + Args: + license_type_id: The license type ID to filter licenses by. + + subscription_id: The subscription ID to get license usage for. + + cursor: Pagination cursor from a previous request. + + end_date: End date for the usage period (YYYY-MM-DD). Defaults to end of current billing + period. + + group_by: How to group the results. Valid values: 'license', 'day'. Can be combined (e.g., + 'license,day'). + + limit: Maximum number of rows in the response data (default 20, max 100). + + start_date: Start date for the usage period (YYYY-MM-DD). Defaults to start of current + billing period. + + 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( + "/licenses/usage", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "license_type_id": license_type_id, + "subscription_id": subscription_id, + "cursor": cursor, + "end_date": end_date, + "group_by": group_by, + "limit": limit, + "start_date": start_date, + }, + usage_get_all_usage_params.UsageGetAllUsageParams, + ), + ), + cast_to=UsageGetAllUsageResponse, + ) + + async def get_usage( + self, + license_id: str, + *, + cursor: Optional[str] | Omit = omit, + end_date: Union[str, date, None] | Omit = omit, + group_by: Optional[str] | Omit = omit, + limit: int | Omit = omit, + start_date: Union[str, date, None] | Omit = omit, + # 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, + ) -> UsageGetUsageResponse: + """ + Returns usage and remaining credits for a specific license over a date range. + + Date range defaults to the current billing period if not specified. + + Args: + cursor: Pagination cursor from a previous request. + + end_date: End date for the usage period (YYYY-MM-DD). Defaults to end of current billing + period. + + group_by: How to group the results. Valid values: 'license', 'day'. Can be combined (e.g., + 'license,day'). + + limit: Maximum number of rows in the response data (default 20, max 100). + + start_date: Start date for the usage period (YYYY-MM-DD). Defaults to start of current + billing period. + + 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 + """ + if not license_id: + raise ValueError(f"Expected a non-empty value for `license_id` but received {license_id!r}") + return await self._get( + path_template("/licenses/{license_id}/usage", license_id=license_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "cursor": cursor, + "end_date": end_date, + "group_by": group_by, + "limit": limit, + "start_date": start_date, + }, + usage_get_usage_params.UsageGetUsageParams, + ), + ), + cast_to=UsageGetUsageResponse, + ) + + +class UsageWithRawResponse: + def __init__(self, usage: Usage) -> None: + self._usage = usage + + self.get_all_usage = _legacy_response.to_raw_response_wrapper( + usage.get_all_usage, + ) + self.get_usage = _legacy_response.to_raw_response_wrapper( + usage.get_usage, + ) + + +class AsyncUsageWithRawResponse: + def __init__(self, usage: AsyncUsage) -> None: + self._usage = usage + + self.get_all_usage = _legacy_response.async_to_raw_response_wrapper( + usage.get_all_usage, + ) + self.get_usage = _legacy_response.async_to_raw_response_wrapper( + usage.get_usage, + ) + + +class UsageWithStreamingResponse: + def __init__(self, usage: Usage) -> None: + self._usage = usage + + self.get_all_usage = to_streamed_response_wrapper( + usage.get_all_usage, + ) + self.get_usage = to_streamed_response_wrapper( + usage.get_usage, + ) + + +class AsyncUsageWithStreamingResponse: + def __init__(self, usage: AsyncUsage) -> None: + self._usage = usage + + self.get_all_usage = async_to_streamed_response_wrapper( + usage.get_all_usage, + ) + self.get_usage = async_to_streamed_response_wrapper( + usage.get_usage, + ) diff --git a/src/orb/resources/metrics.py b/src/orb/resources/metrics.py index bca58b39..11a535d4 100644 --- a/src/orb/resources/metrics.py +++ b/src/orb/resources/metrics.py @@ -8,37 +8,42 @@ import httpx from .. import _legacy_response -from ..types import ( - MetricListResponse, - MetricFetchResponse, - MetricCreateResponse, - metric_list_params, - metric_create_params, -) -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import ( - maybe_transform, - async_maybe_transform, -) +from ..types import metric_list_params, metric_create_params, metric_update_params +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import path_template, 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 ..pagination import SyncPage, AsyncPage -from .._base_client import ( - AsyncPaginator, - make_request_options, -) +from .._base_client import AsyncPaginator, make_request_options +from ..types.billable_metric import BillableMetric __all__ = ["Metrics", "AsyncMetrics"] class Metrics(SyncAPIResource): + """ + The Metric resource represents a calculation of a quantity based on events. + Metrics are defined by the query that transforms raw usage events into meaningful values for your customers. + """ + @cached_property def with_raw_response(self) -> MetricsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -48,19 +53,18 @@ def create( item_id: str, name: str, sql: str, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> MetricCreateResponse: + ) -> BillableMetric: """ - This endpoint is used to create a [metric](../guides/concepts##metric) using a - SQL string. See - [SQL support](../guides/extensibility/advanced-metrics#sql-support) for a + This endpoint is used to create a [metric](/core-concepts###metric) using a SQL + string. See [SQL support](/extensibility/advanced-metrics#sql-support) for a description of constructing SQL queries with examples. Args: @@ -105,29 +109,78 @@ def create( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=MetricCreateResponse, + cast_to=BillableMetric, ) - def list( + def update( self, + metric_id: str, *, - created_at_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, - ) -> SyncPage[MetricListResponse]: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> BillableMetric: + """This endpoint allows you to update the `metadata` property on a metric. + + If you + pass `null` for the metadata value, it will clear any existing metadata for that + invoice. + + Args: + 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 """ - This endpoint is used to fetch [metric](../guides/concepts#metric) details given - a metric identifier. It returns information about the metrics including its - name, description, and item. + if not metric_id: + raise ValueError(f"Expected a non-empty value for `metric_id` but received {metric_id!r}") + return self._put( + path_template("/metrics/{metric_id}", metric_id=metric_id), + body=maybe_transform({"metadata": metadata}, metric_update_params.MetricUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=BillableMetric, + ) + + def list( + self, + *, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + # 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, + ) -> SyncPage[BillableMetric]: + """This endpoint is used to list [metrics](/core-concepts#metric). + + It returns + information about the metrics including its name, description, and item. Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -145,7 +198,7 @@ def list( """ return self._get_api_list( "/metrics", - page=SyncPage[MetricListResponse], + page=SyncPage[BillableMetric], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -163,7 +216,7 @@ def list( metric_list_params.MetricListParams, ), ), - model=MetricListResponse, + model=BillableMetric, ) def fetch( @@ -175,12 +228,12 @@ def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> MetricFetchResponse: - """This endpoint is used to list [metrics](../guides/concepts##metric). - - It returns - information about the metrics including its name, description, and item. + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BillableMetric: + """ + This endpoint is used to fetch [metric](/core-concepts#metric) details given a + metric identifier. It returns information about the metrics including its name, + description, and item. Args: extra_headers: Send extra headers @@ -194,21 +247,37 @@ def fetch( if not metric_id: raise ValueError(f"Expected a non-empty value for `metric_id` but received {metric_id!r}") return self._get( - f"/metrics/{metric_id}", + path_template("/metrics/{metric_id}", metric_id=metric_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=MetricFetchResponse, + cast_to=BillableMetric, ) class AsyncMetrics(AsyncAPIResource): + """ + The Metric resource represents a calculation of a quantity based on events. + Metrics are defined by the query that transforms raw usage events into meaningful values for your customers. + """ + @cached_property def with_raw_response(self) -> AsyncMetricsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -218,19 +287,18 @@ async def create( item_id: str, name: str, sql: str, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> MetricCreateResponse: + ) -> BillableMetric: """ - This endpoint is used to create a [metric](../guides/concepts##metric) using a - SQL string. See - [SQL support](../guides/extensibility/advanced-metrics#sql-support) for a + This endpoint is used to create a [metric](/core-concepts###metric) using a SQL + string. See [SQL support](/extensibility/advanced-metrics#sql-support) for a description of constructing SQL queries with examples. Args: @@ -275,29 +343,78 @@ async def create( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=MetricCreateResponse, + cast_to=BillableMetric, ) - def list( + async def update( self, + metric_id: str, *, - created_at_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, - ) -> AsyncPaginator[MetricListResponse, AsyncPage[MetricListResponse]]: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> BillableMetric: + """This endpoint allows you to update the `metadata` property on a metric. + + If you + pass `null` for the metadata value, it will clear any existing metadata for that + invoice. + + Args: + 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 """ - This endpoint is used to fetch [metric](../guides/concepts#metric) details given - a metric identifier. It returns information about the metrics including its - name, description, and item. + if not metric_id: + raise ValueError(f"Expected a non-empty value for `metric_id` but received {metric_id!r}") + return await self._put( + path_template("/metrics/{metric_id}", metric_id=metric_id), + body=await async_maybe_transform({"metadata": metadata}, metric_update_params.MetricUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=BillableMetric, + ) + + def list( + self, + *, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + # 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, + ) -> AsyncPaginator[BillableMetric, AsyncPage[BillableMetric]]: + """This endpoint is used to list [metrics](/core-concepts#metric). + + It returns + information about the metrics including its name, description, and item. Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -315,7 +432,7 @@ def list( """ return self._get_api_list( "/metrics", - page=AsyncPage[MetricListResponse], + page=AsyncPage[BillableMetric], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -333,7 +450,7 @@ def list( metric_list_params.MetricListParams, ), ), - model=MetricListResponse, + model=BillableMetric, ) async def fetch( @@ -345,12 +462,12 @@ async def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> MetricFetchResponse: - """This endpoint is used to list [metrics](../guides/concepts##metric). - - It returns - information about the metrics including its name, description, and item. + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BillableMetric: + """ + This endpoint is used to fetch [metric](/core-concepts#metric) details given a + metric identifier. It returns information about the metrics including its name, + description, and item. Args: extra_headers: Send extra headers @@ -364,11 +481,11 @@ async def fetch( if not metric_id: raise ValueError(f"Expected a non-empty value for `metric_id` but received {metric_id!r}") return await self._get( - f"/metrics/{metric_id}", + path_template("/metrics/{metric_id}", metric_id=metric_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=MetricFetchResponse, + cast_to=BillableMetric, ) @@ -379,6 +496,9 @@ def __init__(self, metrics: Metrics) -> None: self.create = _legacy_response.to_raw_response_wrapper( metrics.create, ) + self.update = _legacy_response.to_raw_response_wrapper( + metrics.update, + ) self.list = _legacy_response.to_raw_response_wrapper( metrics.list, ) @@ -394,6 +514,9 @@ def __init__(self, metrics: AsyncMetrics) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( metrics.create, ) + self.update = _legacy_response.async_to_raw_response_wrapper( + metrics.update, + ) self.list = _legacy_response.async_to_raw_response_wrapper( metrics.list, ) @@ -409,6 +532,9 @@ def __init__(self, metrics: Metrics) -> None: self.create = to_streamed_response_wrapper( metrics.create, ) + self.update = to_streamed_response_wrapper( + metrics.update, + ) self.list = to_streamed_response_wrapper( metrics.list, ) @@ -424,6 +550,9 @@ def __init__(self, metrics: AsyncMetrics) -> None: self.create = async_to_streamed_response_wrapper( metrics.create, ) + self.update = async_to_streamed_response_wrapper( + metrics.update, + ) self.list = async_to_streamed_response_wrapper( metrics.list, ) diff --git a/src/orb/resources/plans/__init__.py b/src/orb/resources/plans/__init__.py index fa461833..5af74622 100644 --- a/src/orb/resources/plans/__init__.py +++ b/src/orb/resources/plans/__init__.py @@ -8,6 +8,14 @@ PlansWithStreamingResponse, AsyncPlansWithStreamingResponse, ) +from .migrations import ( + Migrations, + AsyncMigrations, + MigrationsWithRawResponse, + AsyncMigrationsWithRawResponse, + MigrationsWithStreamingResponse, + AsyncMigrationsWithStreamingResponse, +) from .external_plan_id import ( ExternalPlanID, AsyncExternalPlanID, @@ -24,6 +32,12 @@ "AsyncExternalPlanIDWithRawResponse", "ExternalPlanIDWithStreamingResponse", "AsyncExternalPlanIDWithStreamingResponse", + "Migrations", + "AsyncMigrations", + "MigrationsWithRawResponse", + "AsyncMigrationsWithRawResponse", + "MigrationsWithStreamingResponse", + "AsyncMigrationsWithStreamingResponse", "Plans", "AsyncPlans", "PlansWithRawResponse", diff --git a/src/orb/resources/plans/external_plan_id.py b/src/orb/resources/plans/external_plan_id.py index df9fd50d..3a0ea6cc 100644 --- a/src/orb/resources/plans/external_plan_id.py +++ b/src/orb/resources/plans/external_plan_id.py @@ -7,61 +7,68 @@ import httpx from ... import _legacy_response -from ...types import Plan -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import ( - maybe_transform, - async_maybe_transform, -) +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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 ...types.plan import Plan from ...types.plans import external_plan_id_update_params -from ..._base_client import ( - make_request_options, -) +from ..._base_client import make_request_options __all__ = ["ExternalPlanID", "AsyncExternalPlanID"] class ExternalPlanID(SyncAPIResource): + """ + The [Plan](/core-concepts#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). + """ + @cached_property def with_raw_response(self) -> ExternalPlanIDWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( self, other_external_plan_id: str, *, - external_plan_id: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + description: Optional[str] | Omit = omit, + external_plan_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Plan: """ - This endpoint is used to fetch [plan](../guides/concepts##plan-and-price) - details given an external_plan_id identifier. It returns information about the - prices included in the plan and their configuration, as well as the product that - the plan is attached to. + This endpoint can be used to update the `external_plan_id`, `description`, and + `metadata` of an existing plan. - ## Serialized prices - - Orb supports a few different pricing models out of the box. Each of these models - is serialized differently in a given [Price](../guides/concepts#plan-and-price) - object. The `model_type` field determines the key for the configuration object - that is present. A detailed explanation of price types can be found in the - [Price schema](../guides/concepts#plan-and-price). + Other fields on a plan are currently immutable. Args: + description: An optional user-defined description of the plan. + external_plan_id: An optional user-defined ID for this plan resource, used throughout the system as an alias for this Plan. Use this field to identify a plan by an existing identifier in your system. @@ -85,9 +92,12 @@ def update( f"Expected a non-empty value for `other_external_plan_id` but received {other_external_plan_id!r}" ) return self._put( - f"/plans/external_plan_id/{other_external_plan_id}", + path_template( + "/plans/external_plan_id/{other_external_plan_id}", other_external_plan_id=other_external_plan_id + ), body=maybe_transform( { + "description": description, "external_plan_id": external_plan_id, "metadata": metadata, }, @@ -112,21 +122,25 @@ def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Plan: """ - This endpoint is used to fetch [plan](../guides/concepts##plan-and-price) - details given an external_plan_id identifier. It returns information about the - prices included in the plan and their configuration, as well as the product that - the plan is attached to. + This endpoint is used to fetch [plan](/core-concepts##plan-and-price) details + given an external_plan_id identifier. It returns information about the prices + included in the plan and their configuration, as well as the product that the + plan is attached to. + + If multiple plans are found to contain the specified external_plan_id, the + active plans will take priority over archived ones, and among those, the + endpoint will return the most recently created plan. ## Serialized prices Orb supports a few different pricing models out of the box. Each of these models - is serialized differently in a given [Price](../guides/concepts#plan-and-price) + is serialized differently in a given [Price](/core-concepts#plan-and-price) object. The `model_type` field determines the key for the configuration object that is present. A detailed explanation of price types can be found in the - [Price schema](../guides/concepts#plan-and-price). " + [Price schema](/core-concepts#plan-and-price). " Args: extra_headers: Send extra headers @@ -140,7 +154,7 @@ def fetch( if not external_plan_id: raise ValueError(f"Expected a non-empty value for `external_plan_id` but received {external_plan_id!r}") return self._get( - f"/plans/external_plan_id/{external_plan_id}", + path_template("/plans/external_plan_id/{external_plan_id}", external_plan_id=external_plan_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -149,43 +163,55 @@ def fetch( class AsyncExternalPlanID(AsyncAPIResource): + """ + The [Plan](/core-concepts#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). + """ + @cached_property def with_raw_response(self) -> AsyncExternalPlanIDWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( self, other_external_plan_id: str, *, - external_plan_id: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + description: Optional[str] | Omit = omit, + external_plan_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Plan: """ - This endpoint is used to fetch [plan](../guides/concepts##plan-and-price) - details given an external_plan_id identifier. It returns information about the - prices included in the plan and their configuration, as well as the product that - the plan is attached to. + This endpoint can be used to update the `external_plan_id`, `description`, and + `metadata` of an existing plan. - ## Serialized prices - - Orb supports a few different pricing models out of the box. Each of these models - is serialized differently in a given [Price](../guides/concepts#plan-and-price) - object. The `model_type` field determines the key for the configuration object - that is present. A detailed explanation of price types can be found in the - [Price schema](../guides/concepts#plan-and-price). + Other fields on a plan are currently immutable. Args: + description: An optional user-defined description of the plan. + external_plan_id: An optional user-defined ID for this plan resource, used throughout the system as an alias for this Plan. Use this field to identify a plan by an existing identifier in your system. @@ -209,9 +235,12 @@ async def update( f"Expected a non-empty value for `other_external_plan_id` but received {other_external_plan_id!r}" ) return await self._put( - f"/plans/external_plan_id/{other_external_plan_id}", + path_template( + "/plans/external_plan_id/{other_external_plan_id}", other_external_plan_id=other_external_plan_id + ), body=await async_maybe_transform( { + "description": description, "external_plan_id": external_plan_id, "metadata": metadata, }, @@ -236,21 +265,25 @@ async def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Plan: """ - This endpoint is used to fetch [plan](../guides/concepts##plan-and-price) - details given an external_plan_id identifier. It returns information about the - prices included in the plan and their configuration, as well as the product that - the plan is attached to. + This endpoint is used to fetch [plan](/core-concepts##plan-and-price) details + given an external_plan_id identifier. It returns information about the prices + included in the plan and their configuration, as well as the product that the + plan is attached to. + + If multiple plans are found to contain the specified external_plan_id, the + active plans will take priority over archived ones, and among those, the + endpoint will return the most recently created plan. ## Serialized prices Orb supports a few different pricing models out of the box. Each of these models - is serialized differently in a given [Price](../guides/concepts#plan-and-price) + is serialized differently in a given [Price](/core-concepts#plan-and-price) object. The `model_type` field determines the key for the configuration object that is present. A detailed explanation of price types can be found in the - [Price schema](../guides/concepts#plan-and-price). " + [Price schema](/core-concepts#plan-and-price). " Args: extra_headers: Send extra headers @@ -264,7 +297,7 @@ async def fetch( if not external_plan_id: raise ValueError(f"Expected a non-empty value for `external_plan_id` but received {external_plan_id!r}") return await self._get( - f"/plans/external_plan_id/{external_plan_id}", + path_template("/plans/external_plan_id/{external_plan_id}", external_plan_id=external_plan_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/orb/resources/plans/migrations.py b/src/orb/resources/plans/migrations.py new file mode 100644 index 00000000..8655180b --- /dev/null +++ b/src/orb/resources/plans/migrations.py @@ -0,0 +1,408 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ... import _legacy_response +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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 ...pagination import SyncPage, AsyncPage +from ...types.plans import migration_list_params +from ..._base_client import AsyncPaginator, make_request_options +from ...types.plans.migration_list_response import MigrationListResponse +from ...types.plans.migration_cancel_response import MigrationCancelResponse +from ...types.plans.migration_retrieve_response import MigrationRetrieveResponse + +__all__ = ["Migrations", "AsyncMigrations"] + + +class Migrations(SyncAPIResource): + """ + The [Plan](/core-concepts#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). + """ + + @cached_property + def with_raw_response(self) -> MigrationsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 MigrationsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MigrationsWithStreamingResponse: + """ + 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 MigrationsWithStreamingResponse(self) + + def retrieve( + self, + migration_id: str, + *, + plan_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MigrationRetrieveResponse: + """ + Fetch migration + + Args: + 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 + """ + if not plan_id: + raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") + if not migration_id: + raise ValueError(f"Expected a non-empty value for `migration_id` but received {migration_id!r}") + return self._get( + path_template("/plans/{plan_id}/migrations/{migration_id}", plan_id=plan_id, migration_id=migration_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MigrationRetrieveResponse, + ) + + def list( + self, + plan_id: str, + *, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + # 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, + ) -> SyncPage[MigrationListResponse]: + """This endpoint returns a list of all migrations for a plan. + + The list of + migrations is ordered starting from the most recently created migration. The + response also includes pagination_metadata, which lets the caller retrieve the + next page of results if they exist. + + Args: + 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. + + 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 + """ + if not plan_id: + raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") + return self._get_api_list( + path_template("/plans/{plan_id}/migrations", plan_id=plan_id), + page=SyncPage[MigrationListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "cursor": cursor, + "limit": limit, + }, + migration_list_params.MigrationListParams, + ), + ), + model=MigrationListResponse, + ) + + def cancel( + self, + migration_id: str, + *, + plan_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> MigrationCancelResponse: + """ + This endpoint cancels a migration. + + Args: + 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 plan_id: + raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") + if not migration_id: + raise ValueError(f"Expected a non-empty value for `migration_id` but received {migration_id!r}") + return self._post( + path_template( + "/plans/{plan_id}/migrations/{migration_id}/cancel", plan_id=plan_id, migration_id=migration_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=MigrationCancelResponse, + ) + + +class AsyncMigrations(AsyncAPIResource): + """ + The [Plan](/core-concepts#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). + """ + + @cached_property + def with_raw_response(self) -> AsyncMigrationsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncMigrationsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMigrationsWithStreamingResponse: + """ + 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 AsyncMigrationsWithStreamingResponse(self) + + async def retrieve( + self, + migration_id: str, + *, + plan_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MigrationRetrieveResponse: + """ + Fetch migration + + Args: + 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 + """ + if not plan_id: + raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") + if not migration_id: + raise ValueError(f"Expected a non-empty value for `migration_id` but received {migration_id!r}") + return await self._get( + path_template("/plans/{plan_id}/migrations/{migration_id}", plan_id=plan_id, migration_id=migration_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MigrationRetrieveResponse, + ) + + def list( + self, + plan_id: str, + *, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + # 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, + ) -> AsyncPaginator[MigrationListResponse, AsyncPage[MigrationListResponse]]: + """This endpoint returns a list of all migrations for a plan. + + The list of + migrations is ordered starting from the most recently created migration. The + response also includes pagination_metadata, which lets the caller retrieve the + next page of results if they exist. + + Args: + 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. + + 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 + """ + if not plan_id: + raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") + return self._get_api_list( + path_template("/plans/{plan_id}/migrations", plan_id=plan_id), + page=AsyncPage[MigrationListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "cursor": cursor, + "limit": limit, + }, + migration_list_params.MigrationListParams, + ), + ), + model=MigrationListResponse, + ) + + async def cancel( + self, + migration_id: str, + *, + plan_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> MigrationCancelResponse: + """ + This endpoint cancels a migration. + + Args: + 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 plan_id: + raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") + if not migration_id: + raise ValueError(f"Expected a non-empty value for `migration_id` but received {migration_id!r}") + return await self._post( + path_template( + "/plans/{plan_id}/migrations/{migration_id}/cancel", plan_id=plan_id, migration_id=migration_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=MigrationCancelResponse, + ) + + +class MigrationsWithRawResponse: + def __init__(self, migrations: Migrations) -> None: + self._migrations = migrations + + self.retrieve = _legacy_response.to_raw_response_wrapper( + migrations.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + migrations.list, + ) + self.cancel = _legacy_response.to_raw_response_wrapper( + migrations.cancel, + ) + + +class AsyncMigrationsWithRawResponse: + def __init__(self, migrations: AsyncMigrations) -> None: + self._migrations = migrations + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + migrations.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + migrations.list, + ) + self.cancel = _legacy_response.async_to_raw_response_wrapper( + migrations.cancel, + ) + + +class MigrationsWithStreamingResponse: + def __init__(self, migrations: Migrations) -> None: + self._migrations = migrations + + self.retrieve = to_streamed_response_wrapper( + migrations.retrieve, + ) + self.list = to_streamed_response_wrapper( + migrations.list, + ) + self.cancel = to_streamed_response_wrapper( + migrations.cancel, + ) + + +class AsyncMigrationsWithStreamingResponse: + def __init__(self, migrations: AsyncMigrations) -> None: + self._migrations = migrations + + self.retrieve = async_to_streamed_response_wrapper( + migrations.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + migrations.list, + ) + self.cancel = async_to_streamed_response_wrapper( + migrations.cancel, + ) diff --git a/src/orb/resources/plans/plans.py b/src/orb/resources/plans/plans.py index e420bad8..9fa3fa35 100644 --- a/src/orb/resources/plans/plans.py +++ b/src/orb/resources/plans/plans.py @@ -9,20 +9,23 @@ import httpx from ... import _legacy_response -from ...types import Plan, plan_list_params, plan_create_params, plan_update_params -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import ( - maybe_transform, - async_maybe_transform, -) +from ...types import plan_list_params, plan_create_params, plan_update_params +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property +from .migrations import ( + Migrations, + AsyncMigrations, + MigrationsWithRawResponse, + AsyncMigrationsWithRawResponse, + MigrationsWithStreamingResponse, + AsyncMigrationsWithStreamingResponse, +) from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ...pagination import SyncPage, AsyncPage -from ..._base_client import ( - AsyncPaginator, - make_request_options, -) +from ...types.plan import Plan +from ..._base_client import AsyncPaginator, make_request_options from .external_plan_id import ( ExternalPlanID, AsyncExternalPlanID, @@ -36,16 +39,47 @@ class Plans(SyncAPIResource): + """ + The [Plan](/core-concepts#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). + """ + @cached_property def external_plan_id(self) -> ExternalPlanID: + """ + The [Plan](/core-concepts#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). + """ return ExternalPlanID(self._client) + @cached_property + def migrations(self) -> Migrations: + """ + The [Plan](/core-concepts#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). + """ + return Migrations(self._client) + @cached_property def with_raw_response(self) -> PlansWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -54,16 +88,20 @@ def create( currency: str, name: str, prices: Iterable[plan_create_params.Price], - default_invoice_memo: Optional[str] | NotGiven = NOT_GIVEN, - external_plan_id: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - net_terms: Optional[int] | NotGiven = NOT_GIVEN, + adjustments: Optional[Iterable[plan_create_params.Adjustment]] | Omit = omit, + default_invoice_memo: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + external_plan_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + net_terms: Optional[int] | Omit = omit, + plan_phases: Optional[Iterable[plan_create_params.PlanPhase]] | Omit = omit, + status: Literal["active", "draft"] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Plan: """ @@ -76,8 +114,13 @@ def create( prices: Prices for this plan. If the plan has phases, this includes prices across all phases of the plan. + adjustments: Adjustments for this plan. If the plan has phases, this includes adjustments + across all phases of the plan. + default_invoice_memo: Free-form text which is available on the invoice PDF and the Orb invoice portal. + description: An optional user-defined description of the plan. + 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`. @@ -86,6 +129,12 @@ def create( date for the invoice. If you intend the invoice to be due on issue, set this to 0. + plan_phases: Configuration of pre-defined phases, each with their own prices and adjustments. + Leave unspecified for plans with a single phase. + + status: The status of the plan to create (either active or draft). If not specified, + this defaults to active. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -103,10 +152,14 @@ def create( "currency": currency, "name": name, "prices": prices, + "adjustments": adjustments, "default_invoice_memo": default_invoice_memo, + "description": description, "external_plan_id": external_plan_id, "metadata": metadata, "net_terms": net_terms, + "plan_phases": plan_phases, + "status": status, }, plan_create_params.PlanCreateParams, ), @@ -124,23 +177,26 @@ def update( self, plan_id: str, *, - external_plan_id: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + description: Optional[str] | Omit = omit, + external_plan_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Plan: """ - This endpoint can be used to update the `external_plan_id`, and `metadata` of an - existing plan. + This endpoint can be used to update the `external_plan_id`, `description`, and + `metadata` of an existing plan. - Other fields on a customer are currently immutable. + Other fields on a plan are currently immutable. Args: + description: An optional user-defined description of the plan. + external_plan_id: An optional user-defined ID for this plan resource, used throughout the system as an alias for this Plan. Use this field to identify a plan by an existing identifier in your system. @@ -162,9 +218,10 @@ def update( if not plan_id: raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") return self._put( - f"/plans/{plan_id}", + path_template("/plans/{plan_id}", plan_id=plan_id), body=maybe_transform( { + "description": description, "external_plan_id": external_plan_id, "metadata": metadata, }, @@ -183,26 +240,26 @@ def update( def list( self, *, - created_at_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - status: Literal["active", "archived", "draft"] | NotGiven = NOT_GIVEN, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + status: Literal["active", "archived", "draft"] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[Plan]: """ - This endpoint returns a list of all [plans](../guides/concepts##plan-and-price) - for an account in a list format. The list of plans is ordered starting from the - most recently created plan. The response also includes - [`pagination_metadata`](../reference/pagination), which lets the caller retrieve - the next page of results if they exist. + This endpoint returns a list of all [plans](/core-concepts#plan-and-price) for + an account in a list format. The list of plans is ordered starting from the most + recently created plan. The response also includes + [`pagination_metadata`](/api-reference/pagination) which lets the caller + retrieve the next page of results if they exist. Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -253,21 +310,21 @@ def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Plan: """ - This endpoint is used to fetch [plan](../guides/concepts##plan-and-price) - details given a plan identifier. It returns information about the prices - included in the plan and their configuration, as well as the product that the - plan is attached to. + This endpoint is used to fetch [plan](/core-concepts#plan-and-price) details + given a plan identifier. It returns information about the prices included in the + plan and their configuration, as well as the product that the plan is attached + to. ## Serialized prices Orb supports a few different pricing models out of the box. Each of these models - is serialized differently in a given [Price](../guides/concepts#plan-and-price) + is serialized differently in a given [Price](/core-concepts#plan-and-price) object. The `model_type` field determines the key for the configuration object that is present. A detailed explanation of price types can be found in the - [Price schema](../guides/concepts#plan-and-price). + [Price schema](/core-concepts#plan-and-price). ## Phases @@ -286,7 +343,7 @@ def fetch( if not plan_id: raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") return self._get( - f"/plans/{plan_id}", + path_template("/plans/{plan_id}", plan_id=plan_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -295,16 +352,47 @@ def fetch( class AsyncPlans(AsyncAPIResource): + """ + The [Plan](/core-concepts#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). + """ + @cached_property def external_plan_id(self) -> AsyncExternalPlanID: + """ + The [Plan](/core-concepts#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). + """ return AsyncExternalPlanID(self._client) + @cached_property + def migrations(self) -> AsyncMigrations: + """ + The [Plan](/core-concepts#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). + """ + return AsyncMigrations(self._client) + @cached_property def with_raw_response(self) -> AsyncPlansWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( @@ -313,16 +401,20 @@ async def create( currency: str, name: str, prices: Iterable[plan_create_params.Price], - default_invoice_memo: Optional[str] | NotGiven = NOT_GIVEN, - external_plan_id: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, - net_terms: Optional[int] | NotGiven = NOT_GIVEN, + adjustments: Optional[Iterable[plan_create_params.Adjustment]] | Omit = omit, + default_invoice_memo: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + external_plan_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + net_terms: Optional[int] | Omit = omit, + plan_phases: Optional[Iterable[plan_create_params.PlanPhase]] | Omit = omit, + status: Literal["active", "draft"] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Plan: """ @@ -335,8 +427,13 @@ async def create( prices: Prices for this plan. If the plan has phases, this includes prices across all phases of the plan. + adjustments: Adjustments for this plan. If the plan has phases, this includes adjustments + across all phases of the plan. + default_invoice_memo: Free-form text which is available on the invoice PDF and the Orb invoice portal. + description: An optional user-defined description of the plan. + 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`. @@ -345,6 +442,12 @@ async def create( date for the invoice. If you intend the invoice to be due on issue, set this to 0. + plan_phases: Configuration of pre-defined phases, each with their own prices and adjustments. + Leave unspecified for plans with a single phase. + + status: The status of the plan to create (either active or draft). If not specified, + this defaults to active. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -362,10 +465,14 @@ async def create( "currency": currency, "name": name, "prices": prices, + "adjustments": adjustments, "default_invoice_memo": default_invoice_memo, + "description": description, "external_plan_id": external_plan_id, "metadata": metadata, "net_terms": net_terms, + "plan_phases": plan_phases, + "status": status, }, plan_create_params.PlanCreateParams, ), @@ -383,23 +490,26 @@ async def update( self, plan_id: str, *, - external_plan_id: Optional[str] | NotGiven = NOT_GIVEN, - metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + description: Optional[str] | Omit = omit, + external_plan_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Plan: """ - This endpoint can be used to update the `external_plan_id`, and `metadata` of an - existing plan. + This endpoint can be used to update the `external_plan_id`, `description`, and + `metadata` of an existing plan. - Other fields on a customer are currently immutable. + Other fields on a plan are currently immutable. Args: + description: An optional user-defined description of the plan. + external_plan_id: An optional user-defined ID for this plan resource, used throughout the system as an alias for this Plan. Use this field to identify a plan by an existing identifier in your system. @@ -421,9 +531,10 @@ async def update( if not plan_id: raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") return await self._put( - f"/plans/{plan_id}", + path_template("/plans/{plan_id}", plan_id=plan_id), body=await async_maybe_transform( { + "description": description, "external_plan_id": external_plan_id, "metadata": metadata, }, @@ -442,26 +553,26 @@ async def update( def list( self, *, - created_at_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - status: Literal["active", "archived", "draft"] | NotGiven = NOT_GIVEN, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + status: Literal["active", "archived", "draft"] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Plan, AsyncPage[Plan]]: """ - This endpoint returns a list of all [plans](../guides/concepts##plan-and-price) - for an account in a list format. The list of plans is ordered starting from the - most recently created plan. The response also includes - [`pagination_metadata`](../reference/pagination), which lets the caller retrieve - the next page of results if they exist. + This endpoint returns a list of all [plans](/core-concepts#plan-and-price) for + an account in a list format. The list of plans is ordered starting from the most + recently created plan. The response also includes + [`pagination_metadata`](/api-reference/pagination) which lets the caller + retrieve the next page of results if they exist. Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -512,21 +623,21 @@ async def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Plan: """ - This endpoint is used to fetch [plan](../guides/concepts##plan-and-price) - details given a plan identifier. It returns information about the prices - included in the plan and their configuration, as well as the product that the - plan is attached to. + This endpoint is used to fetch [plan](/core-concepts#plan-and-price) details + given a plan identifier. It returns information about the prices included in the + plan and their configuration, as well as the product that the plan is attached + to. ## Serialized prices Orb supports a few different pricing models out of the box. Each of these models - is serialized differently in a given [Price](../guides/concepts#plan-and-price) + is serialized differently in a given [Price](/core-concepts#plan-and-price) object. The `model_type` field determines the key for the configuration object that is present. A detailed explanation of price types can be found in the - [Price schema](../guides/concepts#plan-and-price). + [Price schema](/core-concepts#plan-and-price). ## Phases @@ -545,7 +656,7 @@ async def fetch( if not plan_id: raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") return await self._get( - f"/plans/{plan_id}", + path_template("/plans/{plan_id}", plan_id=plan_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -572,8 +683,22 @@ def __init__(self, plans: Plans) -> None: @cached_property def external_plan_id(self) -> ExternalPlanIDWithRawResponse: + """ + The [Plan](/core-concepts#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). + """ return ExternalPlanIDWithRawResponse(self._plans.external_plan_id) + @cached_property + def migrations(self) -> MigrationsWithRawResponse: + """ + The [Plan](/core-concepts#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). + """ + return MigrationsWithRawResponse(self._plans.migrations) + class AsyncPlansWithRawResponse: def __init__(self, plans: AsyncPlans) -> None: @@ -594,8 +719,22 @@ def __init__(self, plans: AsyncPlans) -> None: @cached_property def external_plan_id(self) -> AsyncExternalPlanIDWithRawResponse: + """ + The [Plan](/core-concepts#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). + """ return AsyncExternalPlanIDWithRawResponse(self._plans.external_plan_id) + @cached_property + def migrations(self) -> AsyncMigrationsWithRawResponse: + """ + The [Plan](/core-concepts#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). + """ + return AsyncMigrationsWithRawResponse(self._plans.migrations) + class PlansWithStreamingResponse: def __init__(self, plans: Plans) -> None: @@ -616,8 +755,22 @@ def __init__(self, plans: Plans) -> None: @cached_property def external_plan_id(self) -> ExternalPlanIDWithStreamingResponse: + """ + The [Plan](/core-concepts#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). + """ return ExternalPlanIDWithStreamingResponse(self._plans.external_plan_id) + @cached_property + def migrations(self) -> MigrationsWithStreamingResponse: + """ + The [Plan](/core-concepts#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). + """ + return MigrationsWithStreamingResponse(self._plans.migrations) + class AsyncPlansWithStreamingResponse: def __init__(self, plans: AsyncPlans) -> None: @@ -638,4 +791,18 @@ def __init__(self, plans: AsyncPlans) -> None: @cached_property def external_plan_id(self) -> AsyncExternalPlanIDWithStreamingResponse: + """ + The [Plan](/core-concepts#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). + """ return AsyncExternalPlanIDWithStreamingResponse(self._plans.external_plan_id) + + @cached_property + def migrations(self) -> AsyncMigrationsWithStreamingResponse: + """ + The [Plan](/core-concepts#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). + """ + return AsyncMigrationsWithStreamingResponse(self._plans.migrations) diff --git a/src/orb/resources/prices/external_price_id.py b/src/orb/resources/prices/external_price_id.py index 33c68eef..541874e3 100644 --- a/src/orb/resources/prices/external_price_id.py +++ b/src/orb/resources/prices/external_price_id.py @@ -2,32 +2,107 @@ from __future__ import annotations -from typing import Any, cast +from typing import Any, Dict, Optional, cast import httpx from ... import _legacy_response -from ...types import Price -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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 ..._base_client import make_request_options +from ...types.prices import external_price_id_update_params +from ...types.shared.price import Price __all__ = ["ExternalPriceID", "AsyncExternalPriceID"] class ExternalPriceID(SyncAPIResource): + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ + @cached_property def with_raw_response(self) -> ExternalPriceIDWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( + self, + external_price_id: str, + *, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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 allows you to update the `metadata` property on a price. + + If you + pass null for the metadata value, it will clear any existing metadata for that + price. + + Args: + 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 + """ + if not external_price_id: + raise ValueError(f"Expected a non-empty value for `external_price_id` but received {external_price_id!r}") + return cast( + Price, + self._put( + path_template("/prices/external_price_id/{external_price_id}", external_price_id=external_price_id), + body=maybe_transform( + {"metadata": metadata}, external_price_id_update_params.ExternalPriceIDUpdateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=cast(Any, Price), # Union types cannot be passed in as arguments in the type system + ), + ) + def fetch( self, external_price_id: str, @@ -37,13 +112,13 @@ def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Price: """This endpoint returns a price given an external price id. See the - [price creation API](../reference/create-price) for more information about - external price aliases. + [price creation API](/api-reference/price/create-price) for more information + about external price aliases. Args: extra_headers: Send extra headers @@ -59,7 +134,7 @@ def fetch( return cast( Price, self._get( - f"/prices/external_price_id/{external_price_id}", + path_template("/prices/external_price_id/{external_price_id}", external_price_id=external_price_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -69,14 +144,89 @@ def fetch( class AsyncExternalPriceID(AsyncAPIResource): + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ + @cached_property def with_raw_response(self) -> AsyncExternalPriceIDWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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( + self, + external_price_id: str, + *, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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 allows you to update the `metadata` property on a price. + + If you + pass null for the metadata value, it will clear any existing metadata for that + price. + + Args: + 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 + """ + if not external_price_id: + raise ValueError(f"Expected a non-empty value for `external_price_id` but received {external_price_id!r}") + return cast( + Price, + await self._put( + path_template("/prices/external_price_id/{external_price_id}", external_price_id=external_price_id), + body=await async_maybe_transform( + {"metadata": metadata}, external_price_id_update_params.ExternalPriceIDUpdateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=cast(Any, Price), # Union types cannot be passed in as arguments in the type system + ), + ) + async def fetch( self, external_price_id: str, @@ -86,13 +236,13 @@ async def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Price: """This endpoint returns a price given an external price id. See the - [price creation API](../reference/create-price) for more information about - external price aliases. + [price creation API](/api-reference/price/create-price) for more information + about external price aliases. Args: extra_headers: Send extra headers @@ -108,7 +258,7 @@ async def fetch( return cast( Price, await self._get( - f"/prices/external_price_id/{external_price_id}", + path_template("/prices/external_price_id/{external_price_id}", external_price_id=external_price_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -121,6 +271,9 @@ class ExternalPriceIDWithRawResponse: def __init__(self, external_price_id: ExternalPriceID) -> None: self._external_price_id = external_price_id + self.update = _legacy_response.to_raw_response_wrapper( + external_price_id.update, + ) self.fetch = _legacy_response.to_raw_response_wrapper( external_price_id.fetch, ) @@ -130,6 +283,9 @@ class AsyncExternalPriceIDWithRawResponse: def __init__(self, external_price_id: AsyncExternalPriceID) -> None: self._external_price_id = external_price_id + self.update = _legacy_response.async_to_raw_response_wrapper( + external_price_id.update, + ) self.fetch = _legacy_response.async_to_raw_response_wrapper( external_price_id.fetch, ) @@ -139,6 +295,9 @@ class ExternalPriceIDWithStreamingResponse: def __init__(self, external_price_id: ExternalPriceID) -> None: self._external_price_id = external_price_id + self.update = to_streamed_response_wrapper( + external_price_id.update, + ) self.fetch = to_streamed_response_wrapper( external_price_id.fetch, ) @@ -148,6 +307,9 @@ class AsyncExternalPriceIDWithStreamingResponse: def __init__(self, external_price_id: AsyncExternalPriceID) -> None: self._external_price_id = external_price_id + self.update = async_to_streamed_response_wrapper( + external_price_id.update, + ) self.fetch = async_to_streamed_response_wrapper( external_price_id.fetch, ) diff --git a/src/orb/resources/prices/prices.py b/src/orb/resources/prices/prices.py index 08916872..d45d184d 100644 --- a/src/orb/resources/prices/prices.py +++ b/src/orb/resources/prices/prices.py @@ -2,27 +2,28 @@ from __future__ import annotations -from typing import Any, Dict, Optional, cast, overload -from typing_extensions import Literal +from typing import Any, Dict, Union, Iterable, Optional, cast +from datetime import datetime +from typing_extensions import Literal, overload import httpx from ... import _legacy_response -from ...types import Price, price_list_params, price_create_params -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import ( - required_args, - maybe_transform, - async_maybe_transform, +from ...types import ( + price_list_params, + price_create_params, + price_update_params, + price_evaluate_params, + price_evaluate_multiple_params, + price_evaluate_preview_events_params, ) +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import path_template, required_args, 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 ...pagination import SyncPage, AsyncPage -from ..._base_client import ( - AsyncPaginator, - make_request_options, -) +from ..._base_client import AsyncPaginator, make_request_options from .external_price_id import ( ExternalPriceID, AsyncExternalPriceID, @@ -31,74 +32,135 @@ ExternalPriceIDWithStreamingResponse, AsyncExternalPriceIDWithStreamingResponse, ) +from ...types.shared.price import Price +from ...types.price_evaluate_response import PriceEvaluateResponse +from ...types.shared_params.bulk_config import BulkConfig +from ...types.shared_params.unit_config import UnitConfig +from ...types.shared_params.matrix_config import MatrixConfig +from ...types.shared_params.tiered_config import TieredConfig +from ...types.shared_params.package_config import PackageConfig +from ...types.price_evaluate_multiple_response import PriceEvaluateMultipleResponse +from ...types.price_evaluate_preview_events_response import PriceEvaluatePreviewEventsResponse +from ...types.shared_params.matrix_with_allocation_config import MatrixWithAllocationConfig +from ...types.shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from ...types.shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration __all__ = ["Prices", "AsyncPrices"] class Prices(SyncAPIResource): + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ + @cached_property def external_price_id(self) -> ExternalPriceID: + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ return ExternalPriceID(self._client) @cached_property def with_raw_response(self) -> PricesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, model_type: Literal["unit"], name: str, - unit_config: price_create_params.NewFloatingUnitPriceUnitConfig, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + unit_config: UnitConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingUnitPriceConversionRateConfig] | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. + unit_config: Configuration for unit pricing + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -106,6 +168,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -122,53 +193,72 @@ def create( def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["package"], + model_type: Literal["tiered"], name: str, - package_config: price_create_params.NewFloatingPackagePricePackageConfig, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + tiered_config: TieredConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingTieredPriceConversionRateConfig] | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. + tiered_config: Configuration for tiered pricing + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -176,6 +266,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -192,44 +291,54 @@ def create( def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + bulk_config: BulkConfig, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - matrix_config: price_create_params.NewFloatingMatrixPriceMatrixConfig, - model_type: Literal["matrix"], + model_type: Literal["bulk"], name: str, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingBulkPriceConversionRateConfig] | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) for the + specification of different price model configurations possible in this endpoint. Args: + bulk_config: Configuration for bulk pricing + 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. @@ -239,6 +348,15 @@ def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -246,6 +364,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -262,44 +389,55 @@ def create( def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + bulk_with_filters_config: price_create_params.NewFloatingBulkWithFiltersPriceBulkWithFiltersConfig, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - matrix_with_allocation_config: price_create_params.NewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfig, - model_type: Literal["matrix_with_allocation"], + model_type: Literal["bulk_with_filters"], name: str, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingBulkWithFiltersPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) for the + specification of different price model configurations possible in this endpoint. Args: + bulk_with_filters_config: Configuration for bulk_with_filters pricing + 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. @@ -309,6 +447,15 @@ def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -316,6 +463,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -332,53 +488,72 @@ def create( def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["tiered"], + model_type: Literal["package"], name: str, - tiered_config: price_create_params.NewFloatingTieredPriceTieredConfig, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + package_config: PackageConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingPackagePriceConversionRateConfig] | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. + package_config: Configuration for package pricing + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -386,6 +561,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -402,44 +586,54 @@ def create( def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["tiered_bps"], + matrix_config: MatrixConfig, + model_type: Literal["matrix"], name: str, - tiered_bps_config: price_create_params.NewFloatingTieredBpsPriceTieredBpsConfig, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingMatrixPriceConversionRateConfig] | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + matrix_config: Configuration for matrix pricing + + model_type: The pricing model type name: The name of the price. @@ -449,6 +643,15 @@ def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -456,6 +659,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -472,53 +684,73 @@ def create( def create( self, *, - bps_config: price_create_params.NewFloatingBpsPriceBpsConfig, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["bps"], + model_type: Literal["threshold_total_amount"], name: str, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + threshold_total_amount_config: price_create_params.NewFloatingThresholdTotalAmountPriceThresholdTotalAmountConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingThresholdTotalAmountPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. + threshold_total_amount_config: Configuration for threshold_total_amount pricing + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -526,6 +758,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -542,53 +783,73 @@ def create( def create( self, *, - bulk_bps_config: price_create_params.NewFloatingBulkBpsPriceBulkBpsConfig, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["bulk_bps"], + model_type: Literal["tiered_package"], name: str, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + tiered_package_config: price_create_params.NewFloatingTieredPackagePriceTieredPackageConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingTieredPackagePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. + tiered_package_config: Configuration for tiered_package pricing + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -596,6 +857,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -612,53 +882,73 @@ def create( def create( self, *, - bulk_config: price_create_params.NewFloatingBulkPriceBulkConfig, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["bulk"], + model_type: Literal["tiered_with_minimum"], name: str, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + tiered_with_minimum_config: price_create_params.NewFloatingTieredWithMinimumPriceTieredWithMinimumConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingTieredWithMinimumPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. + tiered_with_minimum_config: Configuration for tiered_with_minimum pricing + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -666,6 +956,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -682,44 +981,55 @@ def create( def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, + grouped_tiered_config: price_create_params.NewFloatingGroupedTieredPriceGroupedTieredConfig, item_id: str, - model_type: Literal["threshold_total_amount"], + model_type: Literal["grouped_tiered"], name: str, - threshold_total_amount_config: Dict[str, object], - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingGroupedTieredPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + grouped_tiered_config: Configuration for grouped_tiered pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. @@ -729,6 +1039,15 @@ def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -736,6 +1055,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -752,53 +1080,75 @@ def create( def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["tiered_package"], + model_type: Literal["tiered_package_with_minimum"], name: str, - tiered_package_config: Dict[str, object], - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + tiered_package_with_minimum_config: price_create_params.NewFloatingTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingTieredPackageWithMinimumPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. + tiered_package_with_minimum_config: Configuration for tiered_package_with_minimum pricing + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -806,6 +1156,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -822,53 +1181,73 @@ def create( def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["tiered_with_minimum"], + model_type: Literal["package_with_allocation"], name: str, - tiered_with_minimum_config: Dict[str, object], - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + package_with_allocation_config: price_create_params.NewFloatingPackageWithAllocationPricePackageWithAllocationConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingPackageWithAllocationPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. + package_with_allocation_config: Configuration for package_with_allocation pricing + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -876,6 +1255,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -892,53 +1280,73 @@ def create( def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["package_with_allocation"], + model_type: Literal["unit_with_percent"], name: str, - package_with_allocation_config: Dict[str, object], - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + unit_with_percent_config: price_create_params.NewFloatingUnitWithPercentPriceUnitWithPercentConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingUnitWithPercentPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. + unit_with_percent_config: Configuration for unit_with_percent pricing + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -946,6 +1354,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -962,44 +1379,55 @@ def create( def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["tiered_package_with_minimum"], + matrix_with_allocation_config: MatrixWithAllocationConfig, + model_type: Literal["matrix_with_allocation"], name: str, - tiered_package_with_minimum_config: Dict[str, object], - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingMatrixWithAllocationPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + matrix_with_allocation_config: Configuration for matrix_with_allocation pricing + + model_type: The pricing model type name: The name of the price. @@ -1009,6 +1437,15 @@ def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -1016,6 +1453,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -1032,44 +1478,57 @@ def create( def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["unit_with_percent"], + matrix_with_threshold_discounts_config: price_create_params.NewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig, + model_type: Literal["matrix_with_threshold_discounts"], name: str, - unit_with_percent_config: Dict[str, object], - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + matrix_with_threshold_discounts_config: Configuration for matrix_with_threshold_discounts pricing + + model_type: The pricing model type name: The name of the price. @@ -1079,6 +1538,15 @@ def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -1086,6 +1554,15 @@ def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -1098,183 +1575,93 @@ def create( """ ... - @required_args( - ["cadence", "currency", "item_id", "model_type", "name", "unit_config"], - ["cadence", "currency", "item_id", "model_type", "name", "package_config"], - ["cadence", "currency", "item_id", "matrix_config", "model_type", "name"], - ["cadence", "currency", "item_id", "matrix_with_allocation_config", "model_type", "name"], - ["cadence", "currency", "item_id", "model_type", "name", "tiered_config"], - ["cadence", "currency", "item_id", "model_type", "name", "tiered_bps_config"], - ["bps_config", "cadence", "currency", "item_id", "model_type", "name"], - ["bulk_bps_config", "cadence", "currency", "item_id", "model_type", "name"], - ["bulk_config", "cadence", "currency", "item_id", "model_type", "name"], - ["cadence", "currency", "item_id", "model_type", "name", "threshold_total_amount_config"], - ["cadence", "currency", "item_id", "model_type", "name", "tiered_package_config"], - ["cadence", "currency", "item_id", "model_type", "name", "tiered_with_minimum_config"], - ["cadence", "currency", "item_id", "model_type", "name", "package_with_allocation_config"], - ["cadence", "currency", "item_id", "model_type", "name", "tiered_package_with_minimum_config"], - ["cadence", "currency", "item_id", "model_type", "name", "unit_with_percent_config"], - ) + @overload def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["unit"] - | Literal["package"] - | Literal["matrix"] - | Literal["matrix_with_allocation"] - | Literal["tiered"] - | Literal["tiered_bps"] - | Literal["bps"] - | Literal["bulk_bps"] - | Literal["bulk"] - | Literal["threshold_total_amount"] - | Literal["tiered_package"] - | Literal["tiered_with_minimum"] - | Literal["package_with_allocation"] - | Literal["tiered_package_with_minimum"] - | Literal["unit_with_percent"], + model_type: Literal["tiered_with_proration"], name: str, - unit_config: price_create_params.NewFloatingUnitPriceUnitConfig | NotGiven = NOT_GIVEN, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, - package_config: price_create_params.NewFloatingPackagePricePackageConfig | NotGiven = NOT_GIVEN, - matrix_config: price_create_params.NewFloatingMatrixPriceMatrixConfig | NotGiven = NOT_GIVEN, - matrix_with_allocation_config: price_create_params.NewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfig - | NotGiven = NOT_GIVEN, - tiered_config: price_create_params.NewFloatingTieredPriceTieredConfig | NotGiven = NOT_GIVEN, - tiered_bps_config: price_create_params.NewFloatingTieredBpsPriceTieredBpsConfig | NotGiven = NOT_GIVEN, - bps_config: price_create_params.NewFloatingBpsPriceBpsConfig | NotGiven = NOT_GIVEN, - bulk_bps_config: price_create_params.NewFloatingBulkBpsPriceBulkBpsConfig | NotGiven = NOT_GIVEN, - bulk_config: price_create_params.NewFloatingBulkPriceBulkConfig | NotGiven = NOT_GIVEN, - threshold_total_amount_config: Dict[str, object] | NotGiven = NOT_GIVEN, - tiered_package_config: Dict[str, object] | NotGiven = NOT_GIVEN, - tiered_with_minimum_config: Dict[str, object] | NotGiven = NOT_GIVEN, - package_with_allocation_config: Dict[str, object] | NotGiven = NOT_GIVEN, - tiered_package_with_minimum_config: Dict[str, object] | NotGiven = NOT_GIVEN, - unit_with_percent_config: Dict[str, object] | NotGiven = NOT_GIVEN, + tiered_with_proration_config: price_create_params.NewFloatingTieredWithProrationPriceTieredWithProrationConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingTieredWithProrationPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Price: - return cast( - Price, - self._post( - "/prices", - body=maybe_transform( - { - "cadence": cadence, - "currency": currency, - "item_id": item_id, - "model_type": model_type, - "name": name, - "unit_config": unit_config, - "billable_metric_id": billable_metric_id, - "billed_in_advance": billed_in_advance, - "external_price_id": external_price_id, - "fixed_price_quantity": fixed_price_quantity, - "invoice_grouping_key": invoice_grouping_key, - "package_config": package_config, - "matrix_config": matrix_config, - "matrix_with_allocation_config": matrix_with_allocation_config, - "tiered_config": tiered_config, - "tiered_bps_config": tiered_bps_config, - "bps_config": bps_config, - "bulk_bps_config": bulk_bps_config, - "bulk_config": bulk_config, - "threshold_total_amount_config": threshold_total_amount_config, - "tiered_package_config": tiered_package_config, - "tiered_with_minimum_config": tiered_with_minimum_config, - "package_with_allocation_config": package_with_allocation_config, - "tiered_package_with_minimum_config": tiered_package_with_minimum_config, - "unit_with_percent_config": unit_with_percent_config, - }, - price_create_params.PriceCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - ), - cast_to=cast(Any, Price), # Union types cannot be passed in as arguments in the type system - ), - ) - - def list( - self, - *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: 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, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[Price]: """ - This endpoint is used to list all add-on prices created using the - [price creation endpoint](../reference/create-price). + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) for the + specification of different price model configurations possible in this endpoint. Args: - cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned - from the initial request. + cadence: The cadence to bill for this price on. - limit: The number of items to fetch. Defaults to 20. + currency: An ISO 4217 currency string for which this price is billed in. - extra_headers: Send extra headers + item_id: The id of the item the price will be associated with. - extra_query: Add additional query parameters to the request + model_type: The pricing model type - extra_body: Add additional JSON properties to the request + name: The name of the price. - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/prices", - page=SyncPage[Price], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "cursor": cursor, - "limit": limit, - }, - price_list_params.PriceListParams, - ), - ), - model=cast(Any, Price), # Union types cannot be passed in as arguments in the type system - ) + tiered_with_proration_config: Configuration for tiered_with_proration pricing - def fetch( - self, - price_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, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Price: - """ - This endpoint returns a price given an identifier. + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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`. - Args: extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1282,85 +1669,82 @@ def fetch( extra_body: Add additional JSON properties to the request timeout: Override the client-level default timeout for this request, in seconds - """ - if not price_id: - raise ValueError(f"Expected a non-empty value for `price_id` but received {price_id!r}") - return cast( - Price, - self._get( - f"/prices/{price_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=cast(Any, Price), # Union types cannot be passed in as arguments in the type system - ), - ) - - -class AsyncPrices(AsyncAPIResource): - @cached_property - def external_price_id(self) -> AsyncExternalPriceID: - return AsyncExternalPriceID(self._client) - - @cached_property - def with_raw_response(self) -> AsyncPricesWithRawResponse: - return AsyncPricesWithRawResponse(self) - @cached_property - def with_streaming_response(self) -> AsyncPricesWithStreamingResponse: - return AsyncPricesWithStreamingResponse(self) + idempotency_key: Specify a custom idempotency key for this request + """ + ... @overload - async def create( + def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["unit"], + model_type: Literal["unit_with_proration"], name: str, - unit_config: price_create_params.NewFloatingUnitPriceUnitConfig, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + unit_with_proration_config: price_create_params.NewFloatingUnitWithProrationPriceUnitWithProrationConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingUnitWithProrationPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. + unit_with_proration_config: Configuration for unit_with_proration pricing + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -1368,6 +1752,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -1381,47 +1774,58 @@ async def create( ... @overload - async def create( + def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, + grouped_allocation_config: price_create_params.NewFloatingGroupedAllocationPriceGroupedAllocationConfig, item_id: str, - model_type: Literal["package"], + model_type: Literal["grouped_allocation"], name: str, - package_config: price_create_params.NewFloatingPackagePricePackageConfig, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingGroupedAllocationPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + grouped_allocation_config: Configuration for grouped_allocation pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. @@ -1431,6 +1835,15 @@ async def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -1438,6 +1851,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -1451,47 +1873,58 @@ async def create( ... @overload - async def create( + def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + bulk_with_proration_config: price_create_params.NewFloatingBulkWithProrationPriceBulkWithProrationConfig, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - matrix_config: price_create_params.NewFloatingMatrixPriceMatrixConfig, - model_type: Literal["matrix"], + model_type: Literal["bulk_with_proration"], name: str, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingBulkWithProrationPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) for the + specification of different price model configurations possible in this endpoint. Args: + bulk_with_proration_config: Configuration for bulk_with_proration pricing + 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. @@ -1501,6 +1934,15 @@ async def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -1508,6 +1950,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -1521,47 +1972,60 @@ async def create( ... @overload - async def create( + def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, + grouped_with_prorated_minimum_config: price_create_params.NewFloatingGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig, item_id: str, - matrix_with_allocation_config: price_create_params.NewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfig, - model_type: Literal["matrix_with_allocation"], + model_type: Literal["grouped_with_prorated_minimum"], name: str, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + grouped_with_prorated_minimum_config: Configuration for grouped_with_prorated_minimum pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. @@ -1571,6 +2035,15 @@ async def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -1578,6 +2051,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -1591,47 +2073,60 @@ async def create( ... @overload - async def create( + def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, + grouped_with_metered_minimum_config: price_create_params.NewFloatingGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig, item_id: str, - model_type: Literal["tiered"], + model_type: Literal["grouped_with_metered_minimum"], name: str, - tiered_config: price_create_params.NewFloatingTieredPriceTieredConfig, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + grouped_with_metered_minimum_config: Configuration for grouped_with_metered_minimum pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. @@ -1641,6 +2136,15 @@ async def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -1648,6 +2152,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -1661,47 +2174,60 @@ async def create( ... @overload - async def create( + def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, + grouped_with_min_max_thresholds_config: price_create_params.NewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig, item_id: str, - model_type: Literal["tiered_bps"], + model_type: Literal["grouped_with_min_max_thresholds"], name: str, - tiered_bps_config: price_create_params.NewFloatingTieredBpsPriceTieredBpsConfig, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + grouped_with_min_max_thresholds_config: Configuration for grouped_with_min_max_thresholds pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. @@ -1711,6 +2237,15 @@ async def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -1718,6 +2253,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -1731,47 +2275,58 @@ async def create( ... @overload - async def create( + def create( self, *, - bps_config: price_create_params.NewFloatingBpsPriceBpsConfig, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["bps"], + matrix_with_display_name_config: price_create_params.NewFloatingMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig, + 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, - external_price_id: Optional[str] | NotGiven = NOT_GIVEN, - fixed_price_quantity: Optional[float] | NotGiven = NOT_GIVEN, - invoice_grouping_key: Optional[str] | NotGiven = NOT_GIVEN, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingMatrixWithDisplayNamePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + matrix_with_display_name_config: Configuration for matrix_with_display_name pricing + + model_type: The pricing model type name: The name of the price. @@ -1781,6 +2336,15 @@ async def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -1788,6 +2352,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -1801,47 +2374,58 @@ async def create( ... @overload - async def create( + def create( self, *, - bulk_bps_config: price_create_params.NewFloatingBulkBpsPriceBulkBpsConfig, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, + grouped_tiered_package_config: price_create_params.NewFloatingGroupedTieredPackagePriceGroupedTieredPackageConfig, item_id: str, - model_type: Literal["bulk_bps"], + model_type: Literal["grouped_tiered_package"], name: str, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingGroupedTieredPackagePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + grouped_tiered_package_config: Configuration for grouped_tiered_package pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. @@ -1851,6 +2435,15 @@ async def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -1858,6 +2451,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -1871,47 +2473,58 @@ async def create( ... @overload - async def create( + def create( self, *, - bulk_config: price_create_params.NewFloatingBulkPriceBulkConfig, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["bulk"], + max_group_tiered_package_config: price_create_params.NewFloatingMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig, + model_type: Literal["max_group_tiered_package"], name: str, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingMaxGroupTieredPackagePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + max_group_tiered_package_config: Configuration for max_group_tiered_package pricing + + model_type: The pricing model type name: The name of the price. @@ -1921,6 +2534,15 @@ async def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -1928,6 +2550,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -1941,56 +2572,78 @@ async def create( ... @overload - async def create( + def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["threshold_total_amount"], + model_type: Literal["scalable_matrix_with_unit_pricing"], name: str, - threshold_total_amount_config: Dict[str, object], - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + scalable_matrix_with_unit_pricing_config: price_create_params.NewFloatingScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. + scalable_matrix_with_unit_pricing_config: Configuration for scalable_matrix_with_unit_pricing pricing + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -1998,6 +2651,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -2011,56 +2673,4171 @@ async def create( ... @overload - async def create( + def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["tiered_package"], + model_type: Literal["scalable_matrix_with_tiered_pricing"], name: str, - tiered_package_config: Dict[str, object], - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + scalable_matrix_with_tiered_pricing_config: price_create_params.NewFloatingScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Price: - """This endpoint is used to create a [price](../reference/price). + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + model_type: The pricing model type + + name: The name of the price. + + scalable_matrix_with_tiered_pricing_config: Configuration for scalable_matrix_with_tiered_pricing pricing + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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"], + cumulative_grouped_bulk_config: price_create_params.NewFloatingCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig, + currency: str, + item_id: str, + model_type: Literal["cumulative_grouped_bulk"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingCumulativeGroupedBulkPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) for the + specification of different price model configurations possible in this endpoint. + + Args: + cadence: The cadence to bill for this price on. + + cumulative_grouped_bulk_config: Configuration for cumulative_grouped_bulk pricing + + currency: An ISO 4217 currency string for which this price is billed in. + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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"], + cumulative_grouped_allocation_config: price_create_params.NewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig, + currency: str, + item_id: str, + model_type: Literal["cumulative_grouped_allocation"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingCumulativeGroupedAllocationPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) for the + specification of different price model configurations possible in this endpoint. + + Args: + cadence: The cadence to bill for this price on. + + cumulative_grouped_allocation_config: Configuration for cumulative_grouped_allocation pricing + + currency: An ISO 4217 currency string for which this price is billed in. + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + daily_credit_allowance_config: price_create_params.NewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig, + item_id: str, + model_type: Literal["daily_credit_allowance"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingDailyCreditAllowancePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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. + + daily_credit_allowance_config: Configuration for daily_credit_allowance pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + metered_allowance_config: price_create_params.NewFloatingMeteredAllowancePriceMeteredAllowanceConfig, + model_type: Literal["metered_allowance"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingMeteredAllowancePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + metered_allowance_config: Configuration for metered_allowance pricing + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + minimum_composite_config: price_create_params.NewFloatingMinimumCompositePriceMinimumCompositeConfig, + model_type: Literal["minimum_composite"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingMinimumCompositePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + minimum_composite_config: Configuration for minimum_composite pricing + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + model_type: Literal["percent"], + name: str, + percent_config: price_create_params.NewFloatingPercentCompositePricePercentConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingPercentCompositePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + model_type: The pricing model type + + name: The name of the price. + + percent_config: Configuration for percent pricing + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + event_output_config: price_create_params.NewFloatingEventOutputPriceEventOutputConfig, + item_id: str, + model_type: Literal["event_output"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingEventOutputPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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. + + event_output_config: Configuration for event_output pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 + """ + ... + + @required_args( + ["cadence", "currency", "item_id", "model_type", "name", "unit_config"], + ["cadence", "currency", "item_id", "model_type", "name", "tiered_config"], + ["bulk_config", "cadence", "currency", "item_id", "model_type", "name"], + ["bulk_with_filters_config", "cadence", "currency", "item_id", "model_type", "name"], + ["cadence", "currency", "item_id", "model_type", "name", "package_config"], + ["cadence", "currency", "item_id", "matrix_config", "model_type", "name"], + ["cadence", "currency", "item_id", "model_type", "name", "threshold_total_amount_config"], + ["cadence", "currency", "item_id", "model_type", "name", "tiered_package_config"], + ["cadence", "currency", "item_id", "model_type", "name", "tiered_with_minimum_config"], + ["cadence", "currency", "grouped_tiered_config", "item_id", "model_type", "name"], + ["cadence", "currency", "item_id", "model_type", "name", "tiered_package_with_minimum_config"], + ["cadence", "currency", "item_id", "model_type", "name", "package_with_allocation_config"], + ["cadence", "currency", "item_id", "model_type", "name", "unit_with_percent_config"], + ["cadence", "currency", "item_id", "matrix_with_allocation_config", "model_type", "name"], + ["cadence", "currency", "item_id", "matrix_with_threshold_discounts_config", "model_type", "name"], + ["cadence", "currency", "item_id", "model_type", "name", "tiered_with_proration_config"], + ["cadence", "currency", "item_id", "model_type", "name", "unit_with_proration_config"], + ["cadence", "currency", "grouped_allocation_config", "item_id", "model_type", "name"], + ["bulk_with_proration_config", "cadence", "currency", "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", "grouped_with_min_max_thresholds_config", "item_id", "model_type", "name"], + ["cadence", "currency", "item_id", "matrix_with_display_name_config", "model_type", "name"], + ["cadence", "currency", "grouped_tiered_package_config", "item_id", "model_type", "name"], + ["cadence", "currency", "item_id", "max_group_tiered_package_config", "model_type", "name"], + ["cadence", "currency", "item_id", "model_type", "name", "scalable_matrix_with_unit_pricing_config"], + ["cadence", "currency", "item_id", "model_type", "name", "scalable_matrix_with_tiered_pricing_config"], + ["cadence", "cumulative_grouped_bulk_config", "currency", "item_id", "model_type", "name"], + ["cadence", "cumulative_grouped_allocation_config", "currency", "item_id", "model_type", "name"], + ["cadence", "currency", "daily_credit_allowance_config", "item_id", "model_type", "name"], + ["cadence", "currency", "item_id", "metered_allowance_config", "model_type", "name"], + ["cadence", "currency", "item_id", "minimum_composite_config", "model_type", "name"], + ["cadence", "currency", "item_id", "model_type", "name", "percent_config"], + ["cadence", "currency", "event_output_config", "item_id", "model_type", "name"], + ) + def create( + self, + *, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], + currency: str, + item_id: str, + model_type: Literal["unit"] + | Literal["tiered"] + | Literal["bulk"] + | Literal["bulk_with_filters"] + | Literal["package"] + | Literal["matrix"] + | Literal["threshold_total_amount"] + | Literal["tiered_package"] + | Literal["tiered_with_minimum"] + | Literal["grouped_tiered"] + | Literal["tiered_package_with_minimum"] + | Literal["package_with_allocation"] + | Literal["unit_with_percent"] + | Literal["matrix_with_allocation"] + | Literal["matrix_with_threshold_discounts"] + | Literal["tiered_with_proration"] + | Literal["unit_with_proration"] + | Literal["grouped_allocation"] + | Literal["bulk_with_proration"] + | Literal["grouped_with_prorated_minimum"] + | Literal["grouped_with_metered_minimum"] + | Literal["grouped_with_min_max_thresholds"] + | Literal["matrix_with_display_name"] + | Literal["grouped_tiered_package"] + | Literal["max_group_tiered_package"] + | Literal["scalable_matrix_with_unit_pricing"] + | Literal["scalable_matrix_with_tiered_pricing"] + | Literal["cumulative_grouped_bulk"] + | Literal["cumulative_grouped_allocation"] + | Literal["daily_credit_allowance"] + | Literal["metered_allowance"] + | Literal["minimum_composite"] + | Literal["percent"] + | Literal["event_output"], + name: str, + unit_config: UnitConfig | Omit = omit, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingUnitPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingTieredPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingBulkPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingBulkWithFiltersPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingPackagePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingMatrixPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingThresholdTotalAmountPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingTieredPackagePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingTieredWithMinimumPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingGroupedTieredPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingTieredPackageWithMinimumPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingPackageWithAllocationPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingUnitWithPercentPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingMatrixWithAllocationPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingTieredWithProrationPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingUnitWithProrationPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingGroupedAllocationPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingBulkWithProrationPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingMatrixWithDisplayNamePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingGroupedTieredPackagePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingMaxGroupTieredPackagePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingCumulativeGroupedBulkPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingCumulativeGroupedAllocationPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingDailyCreditAllowancePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingMeteredAllowancePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingMinimumCompositePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingPercentCompositePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingEventOutputPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + tiered_config: TieredConfig | Omit = omit, + bulk_config: BulkConfig | Omit = omit, + bulk_with_filters_config: price_create_params.NewFloatingBulkWithFiltersPriceBulkWithFiltersConfig + | Omit = omit, + package_config: PackageConfig | Omit = omit, + matrix_config: MatrixConfig | Omit = omit, + threshold_total_amount_config: price_create_params.NewFloatingThresholdTotalAmountPriceThresholdTotalAmountConfig + | Omit = omit, + tiered_package_config: price_create_params.NewFloatingTieredPackagePriceTieredPackageConfig | Omit = omit, + tiered_with_minimum_config: price_create_params.NewFloatingTieredWithMinimumPriceTieredWithMinimumConfig + | Omit = omit, + grouped_tiered_config: price_create_params.NewFloatingGroupedTieredPriceGroupedTieredConfig | Omit = omit, + tiered_package_with_minimum_config: price_create_params.NewFloatingTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig + | Omit = omit, + package_with_allocation_config: price_create_params.NewFloatingPackageWithAllocationPricePackageWithAllocationConfig + | Omit = omit, + unit_with_percent_config: price_create_params.NewFloatingUnitWithPercentPriceUnitWithPercentConfig + | Omit = omit, + matrix_with_allocation_config: MatrixWithAllocationConfig | Omit = omit, + matrix_with_threshold_discounts_config: price_create_params.NewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + | Omit = omit, + tiered_with_proration_config: price_create_params.NewFloatingTieredWithProrationPriceTieredWithProrationConfig + | Omit = omit, + unit_with_proration_config: price_create_params.NewFloatingUnitWithProrationPriceUnitWithProrationConfig + | Omit = omit, + grouped_allocation_config: price_create_params.NewFloatingGroupedAllocationPriceGroupedAllocationConfig + | Omit = omit, + bulk_with_proration_config: price_create_params.NewFloatingBulkWithProrationPriceBulkWithProrationConfig + | Omit = omit, + grouped_with_prorated_minimum_config: price_create_params.NewFloatingGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig + | Omit = omit, + grouped_with_metered_minimum_config: price_create_params.NewFloatingGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig + | Omit = omit, + grouped_with_min_max_thresholds_config: price_create_params.NewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + | Omit = omit, + matrix_with_display_name_config: price_create_params.NewFloatingMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig + | Omit = omit, + grouped_tiered_package_config: price_create_params.NewFloatingGroupedTieredPackagePriceGroupedTieredPackageConfig + | Omit = omit, + max_group_tiered_package_config: price_create_params.NewFloatingMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig + | Omit = omit, + scalable_matrix_with_unit_pricing_config: price_create_params.NewFloatingScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig + | Omit = omit, + scalable_matrix_with_tiered_pricing_config: price_create_params.NewFloatingScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig + | Omit = omit, + cumulative_grouped_bulk_config: price_create_params.NewFloatingCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig + | Omit = omit, + cumulative_grouped_allocation_config: price_create_params.NewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + | Omit = omit, + daily_credit_allowance_config: price_create_params.NewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig + | Omit = omit, + metered_allowance_config: price_create_params.NewFloatingMeteredAllowancePriceMeteredAllowanceConfig + | Omit = omit, + minimum_composite_config: price_create_params.NewFloatingMinimumCompositePriceMinimumCompositeConfig + | Omit = omit, + percent_config: price_create_params.NewFloatingPercentCompositePricePercentConfig | Omit = omit, + event_output_config: price_create_params.NewFloatingEventOutputPriceEventOutputConfig | Omit = omit, + # 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: + return cast( + Price, + self._post( + "/prices", + body=maybe_transform( + { + "cadence": cadence, + "currency": currency, + "item_id": item_id, + "model_type": model_type, + "name": name, + "unit_config": unit_config, + "billable_metric_id": billable_metric_id, + "billed_in_advance": billed_in_advance, + "billing_cycle_configuration": billing_cycle_configuration, + "conversion_rate": conversion_rate, + "conversion_rate_config": conversion_rate_config, + "dimensional_price_configuration": dimensional_price_configuration, + "external_price_id": external_price_id, + "fixed_price_quantity": fixed_price_quantity, + "invoice_grouping_key": invoice_grouping_key, + "invoicing_cycle_configuration": invoicing_cycle_configuration, + "license_type_id": license_type_id, + "metadata": metadata, + "tiered_config": tiered_config, + "bulk_config": bulk_config, + "bulk_with_filters_config": bulk_with_filters_config, + "package_config": package_config, + "matrix_config": matrix_config, + "threshold_total_amount_config": threshold_total_amount_config, + "tiered_package_config": tiered_package_config, + "tiered_with_minimum_config": tiered_with_minimum_config, + "grouped_tiered_config": grouped_tiered_config, + "tiered_package_with_minimum_config": tiered_package_with_minimum_config, + "package_with_allocation_config": package_with_allocation_config, + "unit_with_percent_config": unit_with_percent_config, + "matrix_with_allocation_config": matrix_with_allocation_config, + "matrix_with_threshold_discounts_config": matrix_with_threshold_discounts_config, + "tiered_with_proration_config": tiered_with_proration_config, + "unit_with_proration_config": unit_with_proration_config, + "grouped_allocation_config": grouped_allocation_config, + "bulk_with_proration_config": bulk_with_proration_config, + "grouped_with_prorated_minimum_config": grouped_with_prorated_minimum_config, + "grouped_with_metered_minimum_config": grouped_with_metered_minimum_config, + "grouped_with_min_max_thresholds_config": grouped_with_min_max_thresholds_config, + "matrix_with_display_name_config": matrix_with_display_name_config, + "grouped_tiered_package_config": grouped_tiered_package_config, + "max_group_tiered_package_config": max_group_tiered_package_config, + "scalable_matrix_with_unit_pricing_config": scalable_matrix_with_unit_pricing_config, + "scalable_matrix_with_tiered_pricing_config": scalable_matrix_with_tiered_pricing_config, + "cumulative_grouped_bulk_config": cumulative_grouped_bulk_config, + "cumulative_grouped_allocation_config": cumulative_grouped_allocation_config, + "daily_credit_allowance_config": daily_credit_allowance_config, + "metered_allowance_config": metered_allowance_config, + "minimum_composite_config": minimum_composite_config, + "percent_config": percent_config, + "event_output_config": event_output_config, + }, + price_create_params.PriceCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=cast(Any, Price), # Union types cannot be passed in as arguments in the type system + ), + ) + + def update( + self, + price_id: str, + *, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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 allows you to update the `metadata` property on a price. + + If you + pass null for the metadata value, it will clear any existing metadata for that + price. + + Args: + 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 + """ + if not price_id: + raise ValueError(f"Expected a non-empty value for `price_id` but received {price_id!r}") + return cast( + Price, + self._put( + path_template("/prices/{price_id}", price_id=price_id), + body=maybe_transform({"metadata": metadata}, price_update_params.PriceUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=cast(Any, Price), # Union types cannot be passed in as arguments in the type system + ), + ) + + def list( + self, + *, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + # 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, + ) -> SyncPage[Price]: + """ + This endpoint is used to list all add-on prices created using the + [price creation endpoint](/api-reference/price/create-price). + + Args: + 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. + + 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_api_list( + "/prices", + page=SyncPage[Price], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "cursor": cursor, + "limit": limit, + }, + price_list_params.PriceListParams, + ), + ), + model=cast(Any, Price), # Union types cannot be passed in as arguments in the type system + ) + + def evaluate( + self, + price_id: str, + *, + timeframe_end: Union[str, datetime], + timeframe_start: Union[str, datetime], + customer_id: Optional[str] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + filter: Optional[str] | Omit = omit, + grouping_keys: SequenceNotStr[str] | Omit = omit, + metric_parameter_overrides: Optional[Dict[str, object]] | Omit = omit, + # 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, + ) -> PriceEvaluateResponse: + """ + [NOTE] It is recommended to use the `/v1/prices/evaluate` which offers further + functionality, such as multiple prices, inline price definitions, and querying + over preview events. + + This endpoint is used to evaluate the output of a price for a given customer and + time range. It enables filtering and grouping the output using + [computed properties](/extensibility/advanced-metrics#computed-properties), + supporting the following workflows: + + 1. Showing detailed usage and costs to the end customer. + 2. Auditing subtotals on invoice line items. + + For these workflows, the expressiveness of computed properties in both the + filters and grouping is critical. For example, if you'd like to show your + customer their usage grouped by hour and another property, you can do so with + the following `grouping_keys`: + `["hour_floor_timestamp_millis(timestamp_millis)", "my_property"]`. If you'd + like to examine a customer's usage for a specific property value, you can do so + with the following `filter`: + `my_property = 'foo' AND my_other_property = 'bar'`. + + By default, the start of the time range must be no more than 100 days ago and + the length of the results must be no greater than 1000. Note that this is a POST + endpoint rather than a GET endpoint because it employs a JSON body rather than + query parameters. + + Args: + timeframe_end: The exclusive upper bound for event timestamps + + timeframe_start: The inclusive lower bound for event timestamps + + customer_id: The ID of the customer to which this evaluation is scoped. + + external_customer_id: The external customer ID of the customer to which this evaluation is scoped. + + filter: A boolean + [computed property](/extensibility/advanced-metrics#computed-properties) used to + filter the underlying billable metric + + grouping_keys: Properties (or + [computed properties](/extensibility/advanced-metrics#computed-properties)) used + to group the underlying billable metric + + metric_parameter_overrides: Optional overrides for parameterized billable metric parameters. If the metric + has parameter definitions and no overrides are provided, defaults will be used. + + 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 price_id: + raise ValueError(f"Expected a non-empty value for `price_id` but received {price_id!r}") + return self._post( + path_template("/prices/{price_id}/evaluate", price_id=price_id), + body=maybe_transform( + { + "timeframe_end": timeframe_end, + "timeframe_start": timeframe_start, + "customer_id": customer_id, + "external_customer_id": external_customer_id, + "filter": filter, + "grouping_keys": grouping_keys, + "metric_parameter_overrides": metric_parameter_overrides, + }, + price_evaluate_params.PriceEvaluateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=PriceEvaluateResponse, + ) + + def evaluate_multiple( + self, + *, + timeframe_end: Union[str, datetime], + timeframe_start: Union[str, datetime], + customer_id: Optional[str] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + price_evaluations: Iterable[price_evaluate_multiple_params.PriceEvaluation] | Omit = omit, + # 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, + ) -> PriceEvaluateMultipleResponse: + """ + This endpoint is used to evaluate the output of price(s) for a given customer + and time range over ingested events. It enables filtering and grouping the + output using + [computed properties](/extensibility/advanced-metrics#computed-properties), + supporting the following workflows: + + 1. Showing detailed usage and costs to the end customer. + 2. Auditing subtotals on invoice line items. + + For these workflows, the expressiveness of computed properties in both the + filters and grouping is critical. For example, if you'd like to show your + customer their usage grouped by hour and another property, you can do so with + the following `grouping_keys`: + `["hour_floor_timestamp_millis(timestamp_millis)", "my_property"]`. If you'd + like to examine a customer's usage for a specific property value, you can do so + with the following `filter`: + `my_property = 'foo' AND my_other_property = 'bar'`. + + Prices may either reference existing prices in your Orb account or be defined + inline in the request body. Up to 100 prices can be evaluated in a single + request. + + Prices are evaluated on ingested events and the start of the time range must be + no more than 100 days ago. To evaluate based off a set of provided events, the + [evaluate preview events](/api-reference/price/evaluate-preview-events) endpoint + can be used instead. + + Note that this is a POST endpoint rather than a GET endpoint because it employs + a JSON body rather than query parameters. + + Args: + timeframe_end: The exclusive upper bound for event timestamps + + timeframe_start: The inclusive lower bound for event timestamps + + customer_id: The ID of the customer to which this evaluation is scoped. + + external_customer_id: The external customer ID of the customer to which this evaluation is scoped. + + price_evaluations: List of prices to evaluate (max 100) + + 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( + "/prices/evaluate", + body=maybe_transform( + { + "timeframe_end": timeframe_end, + "timeframe_start": timeframe_start, + "customer_id": customer_id, + "external_customer_id": external_customer_id, + "price_evaluations": price_evaluations, + }, + price_evaluate_multiple_params.PriceEvaluateMultipleParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=PriceEvaluateMultipleResponse, + ) + + def evaluate_preview_events( + self, + *, + timeframe_end: Union[str, datetime], + timeframe_start: Union[str, datetime], + customer_id: Optional[str] | Omit = omit, + events: Iterable[price_evaluate_preview_events_params.Event] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + price_evaluations: Iterable[price_evaluate_preview_events_params.PriceEvaluation] | Omit = omit, + # 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, + ) -> PriceEvaluatePreviewEventsResponse: + """ + This endpoint evaluates prices on preview events instead of actual usage, making + it ideal for building price calculators and cost estimation tools. You can + filter and group results using + [computed properties](/extensibility/advanced-metrics#computed-properties) to + analyze pricing across different dimensions. + + Prices may either reference existing prices in your Orb account or be defined + inline in the request body. The endpoint has the following limitations: + + 1. Up to 100 prices can be evaluated in a single request. + 2. Up to 500 preview events can be provided in a single request. + + A top-level customer_id is required to evaluate the preview events. + Additionally, all events without a customer_id will have the top-level + customer_id added. + + Note that this is a POST endpoint rather than a GET endpoint because it employs + a JSON body rather than query parameters. + + Args: + timeframe_end: The exclusive upper bound for event timestamps + + timeframe_start: The inclusive lower bound for event timestamps + + customer_id: The ID of the customer to which this evaluation is scoped. + + events: List of preview events to use instead of actual usage data + + external_customer_id: The external customer ID of the customer to which this evaluation is scoped. + + price_evaluations: List of prices to evaluate (max 100) + + 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( + "/prices/evaluate_preview_events", + body=maybe_transform( + { + "timeframe_end": timeframe_end, + "timeframe_start": timeframe_start, + "customer_id": customer_id, + "events": events, + "external_customer_id": external_customer_id, + "price_evaluations": price_evaluations, + }, + price_evaluate_preview_events_params.PriceEvaluatePreviewEventsParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=PriceEvaluatePreviewEventsResponse, + ) + + def fetch( + self, + price_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Price: + """ + This endpoint returns a price given an identifier. + + Args: + 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 + """ + if not price_id: + raise ValueError(f"Expected a non-empty value for `price_id` but received {price_id!r}") + return cast( + Price, + self._get( + path_template("/prices/{price_id}", price_id=price_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, Price), # Union types cannot be passed in as arguments in the type system + ), + ) + + +class AsyncPrices(AsyncAPIResource): + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ + + @cached_property + def external_price_id(self) -> AsyncExternalPriceID: + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ + return AsyncExternalPriceID(self._client) + + @cached_property + def with_raw_response(self) -> AsyncPricesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 + async def create( + self, + *, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], + currency: str, + item_id: str, + model_type: Literal["unit"], + name: str, + unit_config: UnitConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingUnitPriceConversionRateConfig] | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + model_type: The pricing model type + + name: The name of the price. + + unit_config: Configuration for unit pricing + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + model_type: Literal["tiered"], + name: str, + tiered_config: TieredConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingTieredPriceConversionRateConfig] | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + model_type: The pricing model type + + name: The name of the price. + + tiered_config: Configuration for tiered pricing + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + *, + bulk_config: BulkConfig, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], + currency: str, + item_id: str, + model_type: Literal["bulk"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingBulkPriceConversionRateConfig] | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) for the + specification of different price model configurations possible in this endpoint. + + Args: + bulk_config: Configuration for bulk pricing + + 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 price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + *, + bulk_with_filters_config: price_create_params.NewFloatingBulkWithFiltersPriceBulkWithFiltersConfig, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], + currency: str, + item_id: str, + model_type: Literal["bulk_with_filters"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingBulkWithFiltersPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) for the + specification of different price model configurations possible in this endpoint. + + Args: + bulk_with_filters_config: Configuration for bulk_with_filters pricing + + 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 price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + model_type: Literal["package"], + name: str, + package_config: PackageConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingPackagePriceConversionRateConfig] | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + model_type: The pricing model type + + name: The name of the price. + + package_config: Configuration for package pricing + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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_config: MatrixConfig, + model_type: Literal["matrix"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingMatrixPriceConversionRateConfig] | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + matrix_config: Configuration for matrix pricing + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + model_type: Literal["threshold_total_amount"], + name: str, + threshold_total_amount_config: price_create_params.NewFloatingThresholdTotalAmountPriceThresholdTotalAmountConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingThresholdTotalAmountPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + model_type: The pricing model type + + name: The name of the price. + + threshold_total_amount_config: Configuration for threshold_total_amount pricing + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + model_type: Literal["tiered_package"], + name: str, + tiered_package_config: price_create_params.NewFloatingTieredPackagePriceTieredPackageConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingTieredPackagePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + model_type: The pricing model type + + name: The name of the price. + + tiered_package_config: Configuration for tiered_package pricing + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + model_type: Literal["tiered_with_minimum"], + name: str, + tiered_with_minimum_config: price_create_params.NewFloatingTieredWithMinimumPriceTieredWithMinimumConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingTieredWithMinimumPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + model_type: The pricing model type + + name: The name of the price. + + tiered_with_minimum_config: Configuration for tiered_with_minimum pricing + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + grouped_tiered_config: price_create_params.NewFloatingGroupedTieredPriceGroupedTieredConfig, + item_id: str, + model_type: Literal["grouped_tiered"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingGroupedTieredPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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. + + grouped_tiered_config: Configuration for grouped_tiered pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + model_type: Literal["tiered_package_with_minimum"], + name: str, + tiered_package_with_minimum_config: price_create_params.NewFloatingTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingTieredPackageWithMinimumPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + model_type: The pricing model type + + name: The name of the price. + + tiered_package_with_minimum_config: Configuration for tiered_package_with_minimum pricing + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + model_type: Literal["package_with_allocation"], + name: str, + package_with_allocation_config: price_create_params.NewFloatingPackageWithAllocationPricePackageWithAllocationConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingPackageWithAllocationPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + model_type: The pricing model type + + name: The name of the price. + + package_with_allocation_config: Configuration for package_with_allocation pricing + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + model_type: Literal["unit_with_percent"], + name: str, + unit_with_percent_config: price_create_params.NewFloatingUnitWithPercentPriceUnitWithPercentConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingUnitWithPercentPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + model_type: The pricing model type + + name: The name of the price. + + unit_with_percent_config: Configuration for unit_with_percent pricing + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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_allocation_config: MatrixWithAllocationConfig, + model_type: Literal["matrix_with_allocation"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingMatrixWithAllocationPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + matrix_with_allocation_config: Configuration for matrix_with_allocation pricing + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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_threshold_discounts_config: price_create_params.NewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig, + model_type: Literal["matrix_with_threshold_discounts"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + matrix_with_threshold_discounts_config: Configuration for matrix_with_threshold_discounts pricing + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + model_type: Literal["tiered_with_proration"], + name: str, + tiered_with_proration_config: price_create_params.NewFloatingTieredWithProrationPriceTieredWithProrationConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingTieredWithProrationPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + model_type: The pricing model type + + name: The name of the price. + + tiered_with_proration_config: Configuration for tiered_with_proration pricing + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + model_type: Literal["unit_with_proration"], + name: str, + unit_with_proration_config: price_create_params.NewFloatingUnitWithProrationPriceUnitWithProrationConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingUnitWithProrationPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + model_type: The pricing model type + + name: The name of the price. + + unit_with_proration_config: Configuration for unit_with_proration pricing + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + grouped_allocation_config: price_create_params.NewFloatingGroupedAllocationPriceGroupedAllocationConfig, + item_id: str, + model_type: Literal["grouped_allocation"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingGroupedAllocationPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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. + + grouped_allocation_config: Configuration for grouped_allocation pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + *, + bulk_with_proration_config: price_create_params.NewFloatingBulkWithProrationPriceBulkWithProrationConfig, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], + currency: str, + item_id: str, + model_type: Literal["bulk_with_proration"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingBulkWithProrationPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) for the + specification of different price model configurations possible in this endpoint. + + Args: + bulk_with_proration_config: Configuration for bulk_with_proration pricing + + 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 price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + grouped_with_prorated_minimum_config: price_create_params.NewFloatingGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig, + item_id: str, + model_type: Literal["grouped_with_prorated_minimum"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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. + + grouped_with_prorated_minimum_config: Configuration for grouped_with_prorated_minimum pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + grouped_with_metered_minimum_config: price_create_params.NewFloatingGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig, + item_id: str, + model_type: Literal["grouped_with_metered_minimum"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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. + + grouped_with_metered_minimum_config: Configuration for grouped_with_metered_minimum pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + grouped_with_min_max_thresholds_config: price_create_params.NewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig, + item_id: str, + model_type: Literal["grouped_with_min_max_thresholds"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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. + + grouped_with_min_max_thresholds_config: Configuration for grouped_with_min_max_thresholds pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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: price_create_params.NewFloatingMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig, + model_type: Literal["matrix_with_display_name"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingMatrixWithDisplayNamePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + matrix_with_display_name_config: Configuration for matrix_with_display_name pricing + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + grouped_tiered_package_config: price_create_params.NewFloatingGroupedTieredPackagePriceGroupedTieredPackageConfig, + item_id: str, + model_type: Literal["grouped_tiered_package"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingGroupedTieredPackagePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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. + + grouped_tiered_package_config: Configuration for grouped_tiered_package pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + max_group_tiered_package_config: price_create_params.NewFloatingMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig, + model_type: Literal["max_group_tiered_package"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingMaxGroupTieredPackagePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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 price will be associated with. + + max_group_tiered_package_config: Configuration for max_group_tiered_package pricing + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + model_type: Literal["scalable_matrix_with_unit_pricing"], + name: str, + scalable_matrix_with_unit_pricing_config: price_create_params.NewFloatingScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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. - 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](/product-catalog/price-configuration) 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 price will be associated with. + + model_type: The pricing model type + + name: The name of the price. + + scalable_matrix_with_unit_pricing_config: Configuration for scalable_matrix_with_unit_pricing pricing + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + model_type: Literal["scalable_matrix_with_tiered_pricing"], + name: str, + scalable_matrix_with_tiered_pricing_config: price_create_params.NewFloatingScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. + scalable_matrix_with_tiered_pricing_config: Configuration for scalable_matrix_with_tiered_pricing pricing + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -2068,6 +6845,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -2084,44 +6870,354 @@ async def create( async def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], + cumulative_grouped_bulk_config: price_create_params.NewFloatingCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig, currency: str, item_id: str, - model_type: Literal["tiered_with_minimum"], + model_type: Literal["cumulative_grouped_bulk"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingCumulativeGroupedBulkPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) for the + specification of different price model configurations possible in this endpoint. + + Args: + cadence: The cadence to bill for this price on. + + cumulative_grouped_bulk_config: Configuration for cumulative_grouped_bulk pricing + + currency: An ISO 4217 currency string for which this price is billed in. + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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"], + cumulative_grouped_allocation_config: price_create_params.NewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig, + currency: str, + item_id: str, + model_type: Literal["cumulative_grouped_allocation"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[ + price_create_params.NewFloatingCumulativeGroupedAllocationPriceConversionRateConfig + ] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) for the + specification of different price model configurations possible in this endpoint. + + Args: + cadence: The cadence to bill for this price on. + + cumulative_grouped_allocation_config: Configuration for cumulative_grouped_allocation pricing + + currency: An ISO 4217 currency string for which this price is billed in. + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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, + daily_credit_allowance_config: price_create_params.NewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig, + item_id: str, + model_type: Literal["daily_credit_allowance"], name: str, - tiered_with_minimum_config: Dict[str, object], - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingDailyCreditAllowancePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Price: - """This endpoint is used to create a [price](../reference/price). + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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](/product-catalog/price-configuration) 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. + + daily_credit_allowance_config: Configuration for daily_credit_allowance pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type + + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + + 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 + """ + ... - 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. + @overload + async def create( + self, + *, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], + currency: str, + item_id: str, + metered_allowance_config: price_create_params.NewFloatingMeteredAllowancePriceMeteredAllowanceConfig, + model_type: Literal["metered_allowance"], + name: str, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingMeteredAllowancePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + metered_allowance_config: Configuration for metered_allowance pricing + + model_type: The pricing model type name: The name of the price. @@ -2131,6 +7227,15 @@ async def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -2138,6 +7243,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -2154,44 +7268,55 @@ async def create( async def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["package_with_allocation"], + minimum_composite_config: price_create_params.NewFloatingMinimumCompositePriceMinimumCompositeConfig, + model_type: Literal["minimum_composite"], name: str, - package_with_allocation_config: Dict[str, object], - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingMinimumCompositePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + minimum_composite_config: Configuration for minimum_composite pricing + + model_type: The pricing model type name: The name of the price. @@ -2201,6 +7326,15 @@ async def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -2208,6 +7342,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -2224,53 +7367,73 @@ async def create( async def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, - model_type: Literal["tiered_package_with_minimum"], + model_type: Literal["percent"], name: str, - tiered_package_with_minimum_config: Dict[str, object], - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + percent_config: price_create_params.NewFloatingPercentCompositePricePercentConfig, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingPercentCompositePriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. + percent_config: Configuration for percent pricing + 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -2278,6 +7441,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -2294,44 +7466,55 @@ async def create( async def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, + event_output_config: price_create_params.NewFloatingEventOutputPriceEventOutputConfig, item_id: str, - model_type: Literal["unit_with_percent"], + model_type: Literal["event_output"], name: str, - unit_with_percent_config: Dict[str, object], - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingEventOutputPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, # 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, + 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. + """ + This endpoint is used to create a [price](/product-catalog/price-configuration). + 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. + See the [Price resource](/product-catalog/price-configuration) 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. + event_output_config: Configuration for event_output pricing + + item_id: The id of the item the price will be associated with. + + model_type: The pricing model type name: The name of the price. @@ -2341,6 +7524,15 @@ async def create( 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. + + conversion_rate_config: The configuration for the rate of the price currency to the invoicing currency. + + dimensional_price_configuration: For dimensional price: specifies a price group and dimension values + external_price_id: An alias for the price. fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units @@ -2348,6 +7540,15 @@ async def create( 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. + + license_type_id: The ID of the license type to associate with this price. + + 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 @@ -2362,70 +7563,191 @@ async def create( @required_args( ["cadence", "currency", "item_id", "model_type", "name", "unit_config"], - ["cadence", "currency", "item_id", "model_type", "name", "package_config"], - ["cadence", "currency", "item_id", "matrix_config", "model_type", "name"], - ["cadence", "currency", "item_id", "matrix_with_allocation_config", "model_type", "name"], ["cadence", "currency", "item_id", "model_type", "name", "tiered_config"], - ["cadence", "currency", "item_id", "model_type", "name", "tiered_bps_config"], - ["bps_config", "cadence", "currency", "item_id", "model_type", "name"], - ["bulk_bps_config", "cadence", "currency", "item_id", "model_type", "name"], ["bulk_config", "cadence", "currency", "item_id", "model_type", "name"], + ["bulk_with_filters_config", "cadence", "currency", "item_id", "model_type", "name"], + ["cadence", "currency", "item_id", "model_type", "name", "package_config"], + ["cadence", "currency", "item_id", "matrix_config", "model_type", "name"], ["cadence", "currency", "item_id", "model_type", "name", "threshold_total_amount_config"], ["cadence", "currency", "item_id", "model_type", "name", "tiered_package_config"], ["cadence", "currency", "item_id", "model_type", "name", "tiered_with_minimum_config"], - ["cadence", "currency", "item_id", "model_type", "name", "package_with_allocation_config"], + ["cadence", "currency", "grouped_tiered_config", "item_id", "model_type", "name"], ["cadence", "currency", "item_id", "model_type", "name", "tiered_package_with_minimum_config"], + ["cadence", "currency", "item_id", "model_type", "name", "package_with_allocation_config"], ["cadence", "currency", "item_id", "model_type", "name", "unit_with_percent_config"], + ["cadence", "currency", "item_id", "matrix_with_allocation_config", "model_type", "name"], + ["cadence", "currency", "item_id", "matrix_with_threshold_discounts_config", "model_type", "name"], + ["cadence", "currency", "item_id", "model_type", "name", "tiered_with_proration_config"], + ["cadence", "currency", "item_id", "model_type", "name", "unit_with_proration_config"], + ["cadence", "currency", "grouped_allocation_config", "item_id", "model_type", "name"], + ["bulk_with_proration_config", "cadence", "currency", "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", "grouped_with_min_max_thresholds_config", "item_id", "model_type", "name"], + ["cadence", "currency", "item_id", "matrix_with_display_name_config", "model_type", "name"], + ["cadence", "currency", "grouped_tiered_package_config", "item_id", "model_type", "name"], + ["cadence", "currency", "item_id", "max_group_tiered_package_config", "model_type", "name"], + ["cadence", "currency", "item_id", "model_type", "name", "scalable_matrix_with_unit_pricing_config"], + ["cadence", "currency", "item_id", "model_type", "name", "scalable_matrix_with_tiered_pricing_config"], + ["cadence", "cumulative_grouped_bulk_config", "currency", "item_id", "model_type", "name"], + ["cadence", "cumulative_grouped_allocation_config", "currency", "item_id", "model_type", "name"], + ["cadence", "currency", "daily_credit_allowance_config", "item_id", "model_type", "name"], + ["cadence", "currency", "item_id", "metered_allowance_config", "model_type", "name"], + ["cadence", "currency", "item_id", "minimum_composite_config", "model_type", "name"], + ["cadence", "currency", "item_id", "model_type", "name", "percent_config"], + ["cadence", "currency", "event_output_config", "item_id", "model_type", "name"], ) async def create( self, *, - cadence: Literal["annual", "monthly", "quarterly", "one_time"], + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], currency: str, item_id: str, model_type: Literal["unit"] - | Literal["package"] - | Literal["matrix"] - | Literal["matrix_with_allocation"] | Literal["tiered"] - | Literal["tiered_bps"] - | Literal["bps"] - | Literal["bulk_bps"] | Literal["bulk"] + | Literal["bulk_with_filters"] + | Literal["package"] + | Literal["matrix"] | Literal["threshold_total_amount"] | Literal["tiered_package"] | Literal["tiered_with_minimum"] - | Literal["package_with_allocation"] + | Literal["grouped_tiered"] | Literal["tiered_package_with_minimum"] - | Literal["unit_with_percent"], + | Literal["package_with_allocation"] + | Literal["unit_with_percent"] + | Literal["matrix_with_allocation"] + | Literal["matrix_with_threshold_discounts"] + | Literal["tiered_with_proration"] + | Literal["unit_with_proration"] + | Literal["grouped_allocation"] + | Literal["bulk_with_proration"] + | Literal["grouped_with_prorated_minimum"] + | Literal["grouped_with_metered_minimum"] + | Literal["grouped_with_min_max_thresholds"] + | Literal["matrix_with_display_name"] + | Literal["grouped_tiered_package"] + | Literal["max_group_tiered_package"] + | Literal["scalable_matrix_with_unit_pricing"] + | Literal["scalable_matrix_with_tiered_pricing"] + | Literal["cumulative_grouped_bulk"] + | Literal["cumulative_grouped_allocation"] + | Literal["daily_credit_allowance"] + | Literal["metered_allowance"] + | Literal["minimum_composite"] + | Literal["percent"] + | Literal["event_output"], name: str, - unit_config: price_create_params.NewFloatingUnitPriceUnitConfig | NotGiven = NOT_GIVEN, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - billed_in_advance: Optional[bool] | 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, - package_config: price_create_params.NewFloatingPackagePricePackageConfig | NotGiven = NOT_GIVEN, - matrix_config: price_create_params.NewFloatingMatrixPriceMatrixConfig | NotGiven = NOT_GIVEN, - matrix_with_allocation_config: price_create_params.NewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfig - | NotGiven = NOT_GIVEN, - tiered_config: price_create_params.NewFloatingTieredPriceTieredConfig | NotGiven = NOT_GIVEN, - tiered_bps_config: price_create_params.NewFloatingTieredBpsPriceTieredBpsConfig | NotGiven = NOT_GIVEN, - bps_config: price_create_params.NewFloatingBpsPriceBpsConfig | NotGiven = NOT_GIVEN, - bulk_bps_config: price_create_params.NewFloatingBulkBpsPriceBulkBpsConfig | NotGiven = NOT_GIVEN, - bulk_config: price_create_params.NewFloatingBulkPriceBulkConfig | NotGiven = NOT_GIVEN, - threshold_total_amount_config: Dict[str, object] | NotGiven = NOT_GIVEN, - tiered_package_config: Dict[str, object] | NotGiven = NOT_GIVEN, - tiered_with_minimum_config: Dict[str, object] | NotGiven = NOT_GIVEN, - package_with_allocation_config: Dict[str, object] | NotGiven = NOT_GIVEN, - tiered_package_with_minimum_config: Dict[str, object] | NotGiven = NOT_GIVEN, - unit_with_percent_config: Dict[str, object] | NotGiven = NOT_GIVEN, + unit_config: UnitConfig | Omit = omit, + billable_metric_id: Optional[str] | Omit = omit, + billed_in_advance: Optional[bool] | Omit = omit, + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + conversion_rate: Optional[float] | Omit = omit, + conversion_rate_config: Optional[price_create_params.NewFloatingUnitPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingTieredPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingBulkPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingBulkWithFiltersPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingPackagePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingMatrixPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingThresholdTotalAmountPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingTieredPackagePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingTieredWithMinimumPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingGroupedTieredPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingTieredPackageWithMinimumPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingPackageWithAllocationPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingUnitWithPercentPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingMatrixWithAllocationPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingTieredWithProrationPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingUnitWithProrationPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingGroupedAllocationPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingBulkWithProrationPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingMatrixWithDisplayNamePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingGroupedTieredPackagePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingMaxGroupTieredPackagePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingCumulativeGroupedBulkPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingCumulativeGroupedAllocationPriceConversionRateConfig] + | Optional[price_create_params.NewFloatingDailyCreditAllowancePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingMeteredAllowancePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingMinimumCompositePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingPercentCompositePriceConversionRateConfig] + | Optional[price_create_params.NewFloatingEventOutputPriceConversionRateConfig] + | Omit = omit, + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] | Omit = omit, + external_price_id: Optional[str] | Omit = omit, + fixed_price_quantity: Optional[float] | Omit = omit, + invoice_grouping_key: Optional[str] | Omit = omit, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] | Omit = omit, + license_type_id: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + tiered_config: TieredConfig | Omit = omit, + bulk_config: BulkConfig | Omit = omit, + bulk_with_filters_config: price_create_params.NewFloatingBulkWithFiltersPriceBulkWithFiltersConfig + | Omit = omit, + package_config: PackageConfig | Omit = omit, + matrix_config: MatrixConfig | Omit = omit, + threshold_total_amount_config: price_create_params.NewFloatingThresholdTotalAmountPriceThresholdTotalAmountConfig + | Omit = omit, + tiered_package_config: price_create_params.NewFloatingTieredPackagePriceTieredPackageConfig | Omit = omit, + tiered_with_minimum_config: price_create_params.NewFloatingTieredWithMinimumPriceTieredWithMinimumConfig + | Omit = omit, + grouped_tiered_config: price_create_params.NewFloatingGroupedTieredPriceGroupedTieredConfig | Omit = omit, + tiered_package_with_minimum_config: price_create_params.NewFloatingTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig + | Omit = omit, + package_with_allocation_config: price_create_params.NewFloatingPackageWithAllocationPricePackageWithAllocationConfig + | Omit = omit, + unit_with_percent_config: price_create_params.NewFloatingUnitWithPercentPriceUnitWithPercentConfig + | Omit = omit, + matrix_with_allocation_config: MatrixWithAllocationConfig | Omit = omit, + matrix_with_threshold_discounts_config: price_create_params.NewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + | Omit = omit, + tiered_with_proration_config: price_create_params.NewFloatingTieredWithProrationPriceTieredWithProrationConfig + | Omit = omit, + unit_with_proration_config: price_create_params.NewFloatingUnitWithProrationPriceUnitWithProrationConfig + | Omit = omit, + grouped_allocation_config: price_create_params.NewFloatingGroupedAllocationPriceGroupedAllocationConfig + | Omit = omit, + bulk_with_proration_config: price_create_params.NewFloatingBulkWithProrationPriceBulkWithProrationConfig + | Omit = omit, + grouped_with_prorated_minimum_config: price_create_params.NewFloatingGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig + | Omit = omit, + grouped_with_metered_minimum_config: price_create_params.NewFloatingGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig + | Omit = omit, + grouped_with_min_max_thresholds_config: price_create_params.NewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + | Omit = omit, + matrix_with_display_name_config: price_create_params.NewFloatingMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig + | Omit = omit, + grouped_tiered_package_config: price_create_params.NewFloatingGroupedTieredPackagePriceGroupedTieredPackageConfig + | Omit = omit, + max_group_tiered_package_config: price_create_params.NewFloatingMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig + | Omit = omit, + scalable_matrix_with_unit_pricing_config: price_create_params.NewFloatingScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig + | Omit = omit, + scalable_matrix_with_tiered_pricing_config: price_create_params.NewFloatingScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig + | Omit = omit, + cumulative_grouped_bulk_config: price_create_params.NewFloatingCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig + | Omit = omit, + cumulative_grouped_allocation_config: price_create_params.NewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + | Omit = omit, + daily_credit_allowance_config: price_create_params.NewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig + | Omit = omit, + metered_allowance_config: price_create_params.NewFloatingMeteredAllowancePriceMeteredAllowanceConfig + | Omit = omit, + minimum_composite_config: price_create_params.NewFloatingMinimumCompositePriceMinimumCompositeConfig + | Omit = omit, + percent_config: price_create_params.NewFloatingPercentCompositePricePercentConfig | Omit = omit, + event_output_config: price_create_params.NewFloatingEventOutputPriceEventOutputConfig | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Price: return cast( @@ -2442,23 +7764,49 @@ async def create( "unit_config": unit_config, "billable_metric_id": billable_metric_id, "billed_in_advance": billed_in_advance, + "billing_cycle_configuration": billing_cycle_configuration, + "conversion_rate": conversion_rate, + "conversion_rate_config": conversion_rate_config, + "dimensional_price_configuration": dimensional_price_configuration, "external_price_id": external_price_id, "fixed_price_quantity": fixed_price_quantity, "invoice_grouping_key": invoice_grouping_key, - "package_config": package_config, - "matrix_config": matrix_config, - "matrix_with_allocation_config": matrix_with_allocation_config, + "invoicing_cycle_configuration": invoicing_cycle_configuration, + "license_type_id": license_type_id, + "metadata": metadata, "tiered_config": tiered_config, - "tiered_bps_config": tiered_bps_config, - "bps_config": bps_config, - "bulk_bps_config": bulk_bps_config, "bulk_config": bulk_config, + "bulk_with_filters_config": bulk_with_filters_config, + "package_config": package_config, + "matrix_config": matrix_config, "threshold_total_amount_config": threshold_total_amount_config, "tiered_package_config": tiered_package_config, "tiered_with_minimum_config": tiered_with_minimum_config, - "package_with_allocation_config": package_with_allocation_config, + "grouped_tiered_config": grouped_tiered_config, "tiered_package_with_minimum_config": tiered_package_with_minimum_config, + "package_with_allocation_config": package_with_allocation_config, "unit_with_percent_config": unit_with_percent_config, + "matrix_with_allocation_config": matrix_with_allocation_config, + "matrix_with_threshold_discounts_config": matrix_with_threshold_discounts_config, + "tiered_with_proration_config": tiered_with_proration_config, + "unit_with_proration_config": unit_with_proration_config, + "grouped_allocation_config": grouped_allocation_config, + "bulk_with_proration_config": bulk_with_proration_config, + "grouped_with_prorated_minimum_config": grouped_with_prorated_minimum_config, + "grouped_with_metered_minimum_config": grouped_with_metered_minimum_config, + "grouped_with_min_max_thresholds_config": grouped_with_min_max_thresholds_config, + "matrix_with_display_name_config": matrix_with_display_name_config, + "grouped_tiered_package_config": grouped_tiered_package_config, + "max_group_tiered_package_config": max_group_tiered_package_config, + "scalable_matrix_with_unit_pricing_config": scalable_matrix_with_unit_pricing_config, + "scalable_matrix_with_tiered_pricing_config": scalable_matrix_with_tiered_pricing_config, + "cumulative_grouped_bulk_config": cumulative_grouped_bulk_config, + "cumulative_grouped_allocation_config": cumulative_grouped_allocation_config, + "daily_credit_allowance_config": daily_credit_allowance_config, + "metered_allowance_config": metered_allowance_config, + "minimum_composite_config": minimum_composite_config, + "percent_config": percent_config, + "event_output_config": event_output_config, }, price_create_params.PriceCreateParams, ), @@ -2473,21 +7821,73 @@ async def create( ), ) + async def update( + self, + price_id: str, + *, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + # 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 allows you to update the `metadata` property on a price. + + If you + pass null for the metadata value, it will clear any existing metadata for that + price. + + Args: + 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 + """ + if not price_id: + raise ValueError(f"Expected a non-empty value for `price_id` but received {price_id!r}") + return cast( + Price, + await self._put( + path_template("/prices/{price_id}", price_id=price_id), + body=await async_maybe_transform({"metadata": metadata}, price_update_params.PriceUpdateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=cast(Any, Price), # Union types cannot be passed in as arguments in the type system + ), + ) + def list( self, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Price, AsyncPage[Price]]: """ This endpoint is used to list all add-on prices created using the - [price creation endpoint](../reference/create-price). + [price creation endpoint](/api-reference/price/create-price). Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -2522,6 +7922,281 @@ def list( model=cast(Any, Price), # Union types cannot be passed in as arguments in the type system ) + async def evaluate( + self, + price_id: str, + *, + timeframe_end: Union[str, datetime], + timeframe_start: Union[str, datetime], + customer_id: Optional[str] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + filter: Optional[str] | Omit = omit, + grouping_keys: SequenceNotStr[str] | Omit = omit, + metric_parameter_overrides: Optional[Dict[str, object]] | Omit = omit, + # 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, + ) -> PriceEvaluateResponse: + """ + [NOTE] It is recommended to use the `/v1/prices/evaluate` which offers further + functionality, such as multiple prices, inline price definitions, and querying + over preview events. + + This endpoint is used to evaluate the output of a price for a given customer and + time range. It enables filtering and grouping the output using + [computed properties](/extensibility/advanced-metrics#computed-properties), + supporting the following workflows: + + 1. Showing detailed usage and costs to the end customer. + 2. Auditing subtotals on invoice line items. + + For these workflows, the expressiveness of computed properties in both the + filters and grouping is critical. For example, if you'd like to show your + customer their usage grouped by hour and another property, you can do so with + the following `grouping_keys`: + `["hour_floor_timestamp_millis(timestamp_millis)", "my_property"]`. If you'd + like to examine a customer's usage for a specific property value, you can do so + with the following `filter`: + `my_property = 'foo' AND my_other_property = 'bar'`. + + By default, the start of the time range must be no more than 100 days ago and + the length of the results must be no greater than 1000. Note that this is a POST + endpoint rather than a GET endpoint because it employs a JSON body rather than + query parameters. + + Args: + timeframe_end: The exclusive upper bound for event timestamps + + timeframe_start: The inclusive lower bound for event timestamps + + customer_id: The ID of the customer to which this evaluation is scoped. + + external_customer_id: The external customer ID of the customer to which this evaluation is scoped. + + filter: A boolean + [computed property](/extensibility/advanced-metrics#computed-properties) used to + filter the underlying billable metric + + grouping_keys: Properties (or + [computed properties](/extensibility/advanced-metrics#computed-properties)) used + to group the underlying billable metric + + metric_parameter_overrides: Optional overrides for parameterized billable metric parameters. If the metric + has parameter definitions and no overrides are provided, defaults will be used. + + 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 price_id: + raise ValueError(f"Expected a non-empty value for `price_id` but received {price_id!r}") + return await self._post( + path_template("/prices/{price_id}/evaluate", price_id=price_id), + body=await async_maybe_transform( + { + "timeframe_end": timeframe_end, + "timeframe_start": timeframe_start, + "customer_id": customer_id, + "external_customer_id": external_customer_id, + "filter": filter, + "grouping_keys": grouping_keys, + "metric_parameter_overrides": metric_parameter_overrides, + }, + price_evaluate_params.PriceEvaluateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=PriceEvaluateResponse, + ) + + async def evaluate_multiple( + self, + *, + timeframe_end: Union[str, datetime], + timeframe_start: Union[str, datetime], + customer_id: Optional[str] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + price_evaluations: Iterable[price_evaluate_multiple_params.PriceEvaluation] | Omit = omit, + # 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, + ) -> PriceEvaluateMultipleResponse: + """ + This endpoint is used to evaluate the output of price(s) for a given customer + and time range over ingested events. It enables filtering and grouping the + output using + [computed properties](/extensibility/advanced-metrics#computed-properties), + supporting the following workflows: + + 1. Showing detailed usage and costs to the end customer. + 2. Auditing subtotals on invoice line items. + + For these workflows, the expressiveness of computed properties in both the + filters and grouping is critical. For example, if you'd like to show your + customer their usage grouped by hour and another property, you can do so with + the following `grouping_keys`: + `["hour_floor_timestamp_millis(timestamp_millis)", "my_property"]`. If you'd + like to examine a customer's usage for a specific property value, you can do so + with the following `filter`: + `my_property = 'foo' AND my_other_property = 'bar'`. + + Prices may either reference existing prices in your Orb account or be defined + inline in the request body. Up to 100 prices can be evaluated in a single + request. + + Prices are evaluated on ingested events and the start of the time range must be + no more than 100 days ago. To evaluate based off a set of provided events, the + [evaluate preview events](/api-reference/price/evaluate-preview-events) endpoint + can be used instead. + + Note that this is a POST endpoint rather than a GET endpoint because it employs + a JSON body rather than query parameters. + + Args: + timeframe_end: The exclusive upper bound for event timestamps + + timeframe_start: The inclusive lower bound for event timestamps + + customer_id: The ID of the customer to which this evaluation is scoped. + + external_customer_id: The external customer ID of the customer to which this evaluation is scoped. + + price_evaluations: List of prices to evaluate (max 100) + + 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( + "/prices/evaluate", + body=await async_maybe_transform( + { + "timeframe_end": timeframe_end, + "timeframe_start": timeframe_start, + "customer_id": customer_id, + "external_customer_id": external_customer_id, + "price_evaluations": price_evaluations, + }, + price_evaluate_multiple_params.PriceEvaluateMultipleParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=PriceEvaluateMultipleResponse, + ) + + async def evaluate_preview_events( + self, + *, + timeframe_end: Union[str, datetime], + timeframe_start: Union[str, datetime], + customer_id: Optional[str] | Omit = omit, + events: Iterable[price_evaluate_preview_events_params.Event] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + price_evaluations: Iterable[price_evaluate_preview_events_params.PriceEvaluation] | Omit = omit, + # 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, + ) -> PriceEvaluatePreviewEventsResponse: + """ + This endpoint evaluates prices on preview events instead of actual usage, making + it ideal for building price calculators and cost estimation tools. You can + filter and group results using + [computed properties](/extensibility/advanced-metrics#computed-properties) to + analyze pricing across different dimensions. + + Prices may either reference existing prices in your Orb account or be defined + inline in the request body. The endpoint has the following limitations: + + 1. Up to 100 prices can be evaluated in a single request. + 2. Up to 500 preview events can be provided in a single request. + + A top-level customer_id is required to evaluate the preview events. + Additionally, all events without a customer_id will have the top-level + customer_id added. + + Note that this is a POST endpoint rather than a GET endpoint because it employs + a JSON body rather than query parameters. + + Args: + timeframe_end: The exclusive upper bound for event timestamps + + timeframe_start: The inclusive lower bound for event timestamps + + customer_id: The ID of the customer to which this evaluation is scoped. + + events: List of preview events to use instead of actual usage data + + external_customer_id: The external customer ID of the customer to which this evaluation is scoped. + + price_evaluations: List of prices to evaluate (max 100) + + 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( + "/prices/evaluate_preview_events", + body=await async_maybe_transform( + { + "timeframe_end": timeframe_end, + "timeframe_start": timeframe_start, + "customer_id": customer_id, + "events": events, + "external_customer_id": external_customer_id, + "price_evaluations": price_evaluations, + }, + price_evaluate_preview_events_params.PriceEvaluatePreviewEventsParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=PriceEvaluatePreviewEventsResponse, + ) + async def fetch( self, price_id: str, @@ -2531,7 +8206,7 @@ async def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Price: """ This endpoint returns a price given an identifier. @@ -2550,7 +8225,7 @@ async def fetch( return cast( Price, await self._get( - f"/prices/{price_id}", + path_template("/prices/{price_id}", price_id=price_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -2566,15 +8241,36 @@ def __init__(self, prices: Prices) -> None: self.create = _legacy_response.to_raw_response_wrapper( prices.create, ) + self.update = _legacy_response.to_raw_response_wrapper( + prices.update, + ) self.list = _legacy_response.to_raw_response_wrapper( prices.list, ) + self.evaluate = _legacy_response.to_raw_response_wrapper( + prices.evaluate, + ) + self.evaluate_multiple = _legacy_response.to_raw_response_wrapper( + prices.evaluate_multiple, + ) + self.evaluate_preview_events = _legacy_response.to_raw_response_wrapper( + prices.evaluate_preview_events, + ) self.fetch = _legacy_response.to_raw_response_wrapper( prices.fetch, ) @cached_property def external_price_id(self) -> ExternalPriceIDWithRawResponse: + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ return ExternalPriceIDWithRawResponse(self._prices.external_price_id) @@ -2585,15 +8281,36 @@ def __init__(self, prices: AsyncPrices) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( prices.create, ) + self.update = _legacy_response.async_to_raw_response_wrapper( + prices.update, + ) self.list = _legacy_response.async_to_raw_response_wrapper( prices.list, ) + self.evaluate = _legacy_response.async_to_raw_response_wrapper( + prices.evaluate, + ) + self.evaluate_multiple = _legacy_response.async_to_raw_response_wrapper( + prices.evaluate_multiple, + ) + self.evaluate_preview_events = _legacy_response.async_to_raw_response_wrapper( + prices.evaluate_preview_events, + ) self.fetch = _legacy_response.async_to_raw_response_wrapper( prices.fetch, ) @cached_property def external_price_id(self) -> AsyncExternalPriceIDWithRawResponse: + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ return AsyncExternalPriceIDWithRawResponse(self._prices.external_price_id) @@ -2604,15 +8321,36 @@ def __init__(self, prices: Prices) -> None: self.create = to_streamed_response_wrapper( prices.create, ) + self.update = to_streamed_response_wrapper( + prices.update, + ) self.list = to_streamed_response_wrapper( prices.list, ) + self.evaluate = to_streamed_response_wrapper( + prices.evaluate, + ) + self.evaluate_multiple = to_streamed_response_wrapper( + prices.evaluate_multiple, + ) + self.evaluate_preview_events = to_streamed_response_wrapper( + prices.evaluate_preview_events, + ) self.fetch = to_streamed_response_wrapper( prices.fetch, ) @cached_property def external_price_id(self) -> ExternalPriceIDWithStreamingResponse: + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ return ExternalPriceIDWithStreamingResponse(self._prices.external_price_id) @@ -2623,13 +8361,34 @@ def __init__(self, prices: AsyncPrices) -> None: self.create = async_to_streamed_response_wrapper( prices.create, ) + self.update = async_to_streamed_response_wrapper( + prices.update, + ) self.list = async_to_streamed_response_wrapper( prices.list, ) + self.evaluate = async_to_streamed_response_wrapper( + prices.evaluate, + ) + self.evaluate_multiple = async_to_streamed_response_wrapper( + prices.evaluate_multiple, + ) + self.evaluate_preview_events = async_to_streamed_response_wrapper( + prices.evaluate_preview_events, + ) self.fetch = async_to_streamed_response_wrapper( prices.fetch, ) @cached_property def external_price_id(self) -> AsyncExternalPriceIDWithStreamingResponse: + """ + 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. + + For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + """ return AsyncExternalPriceIDWithStreamingResponse(self._prices.external_price_id) diff --git a/src/orb/resources/subscription_changes.py b/src/orb/resources/subscription_changes.py new file mode 100644 index 00000000..65d3309d --- /dev/null +++ b/src/orb/resources/subscription_changes.py @@ -0,0 +1,597 @@ +# 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 date +from typing_extensions import Literal + +import httpx + +from .. import _legacy_response +from ..types import subscription_change_list_params, subscription_change_apply_params +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import path_template, 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 ..pagination import SyncPage, AsyncPage +from .._base_client import AsyncPaginator, make_request_options +from ..types.subscription_change_list_response import SubscriptionChangeListResponse +from ..types.subscription_change_apply_response import SubscriptionChangeApplyResponse +from ..types.subscription_change_cancel_response import SubscriptionChangeCancelResponse +from ..types.subscription_change_retrieve_response import SubscriptionChangeRetrieveResponse + +__all__ = ["SubscriptionChanges", "AsyncSubscriptionChanges"] + + +class SubscriptionChanges(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SubscriptionChangesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 SubscriptionChangesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SubscriptionChangesWithStreamingResponse: + """ + 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 SubscriptionChangesWithStreamingResponse(self) + + def retrieve( + self, + subscription_change_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SubscriptionChangeRetrieveResponse: + """ + This endpoint returns a subscription change given an identifier. + + A subscription change is created by including + `Create-Pending-Subscription-Change: True` in the header of a subscription + mutation API call (e.g. + [create subscription endpoint](/api-reference/subscription/create-subscription), + [schedule plan change endpoint](/api-reference/subscription/schedule-plan-change), + ...). The subscription change will be referenced by the + `pending_subscription_change` field in the response. + + Args: + 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 + """ + if not subscription_change_id: + raise ValueError( + f"Expected a non-empty value for `subscription_change_id` but received {subscription_change_id!r}" + ) + return self._get( + path_template( + "/subscription_changes/{subscription_change_id}", subscription_change_id=subscription_change_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SubscriptionChangeRetrieveResponse, + ) + + def list( + self, + *, + cursor: Optional[str] | Omit = omit, + customer_id: Optional[str] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + limit: int | Omit = omit, + status: Optional[Literal["pending", "applied", "cancelled"]] | Omit = omit, + # 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, + ) -> SyncPage[SubscriptionChangeListResponse]: + """This endpoint returns a list of pending subscription changes for a customer. + + Use + the [Fetch Subscription Change](fetch-subscription-change) endpoint to retrieve + the expected subscription state after the pending change is applied. + + Args: + 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. + + 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_api_list( + "/subscription_changes", + page=SyncPage[SubscriptionChangeListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "cursor": cursor, + "customer_id": customer_id, + "external_customer_id": external_customer_id, + "limit": limit, + "status": status, + }, + subscription_change_list_params.SubscriptionChangeListParams, + ), + ), + model=SubscriptionChangeListResponse, + ) + + def apply( + self, + subscription_change_id: str, + *, + description: Optional[str] | Omit = omit, + mark_as_paid: Optional[bool] | Omit = omit, + payment_external_id: Optional[str] | Omit = omit, + payment_notes: Optional[str] | Omit = omit, + payment_received_date: Union[str, date, None] | Omit = omit, + previously_collected_amount: Optional[str] | Omit = omit, + # 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, + ) -> SubscriptionChangeApplyResponse: + """Apply a subscription change to perform the intended action. + + If a positive amount + is passed with a request to this endpoint, any eligible invoices that were + created will be issued immediately if they only contain in-advance fees. + + Args: + description: Description to apply to the balance transaction representing this credit. + + mark_as_paid: Mark all pending invoices that are payable as paid. If amount is also provided, + mark as paid and credit the difference to the customer's balance. + + payment_external_id: An optional external ID to associate with the payment. Only applicable when + mark_as_paid is true. + + payment_notes: Optional notes about the payment. Only applicable when mark_as_paid is true. + + payment_received_date: A date string to specify the date the payment was received. Only applicable when + mark_as_paid is true. If not provided, defaults to the current date. + + previously_collected_amount: Amount already collected to apply to the customer's balance. If mark_as_paid is + also provided, credit the difference to the customer's balance. + + 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_change_id: + raise ValueError( + f"Expected a non-empty value for `subscription_change_id` but received {subscription_change_id!r}" + ) + return self._post( + path_template( + "/subscription_changes/{subscription_change_id}/apply", subscription_change_id=subscription_change_id + ), + body=maybe_transform( + { + "description": description, + "mark_as_paid": mark_as_paid, + "payment_external_id": payment_external_id, + "payment_notes": payment_notes, + "payment_received_date": payment_received_date, + "previously_collected_amount": previously_collected_amount, + }, + subscription_change_apply_params.SubscriptionChangeApplyParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=SubscriptionChangeApplyResponse, + ) + + def cancel( + self, + subscription_change_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> SubscriptionChangeCancelResponse: + """Cancel a subscription change. + + The change can no longer be applied. A + subscription can only have one "pending" change at a time - use this endpoint to + cancel an existing change before creating a new one. + + Args: + 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_change_id: + raise ValueError( + f"Expected a non-empty value for `subscription_change_id` but received {subscription_change_id!r}" + ) + return self._post( + path_template( + "/subscription_changes/{subscription_change_id}/cancel", subscription_change_id=subscription_change_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=SubscriptionChangeCancelResponse, + ) + + +class AsyncSubscriptionChanges(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSubscriptionChangesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncSubscriptionChangesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSubscriptionChangesWithStreamingResponse: + """ + 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 AsyncSubscriptionChangesWithStreamingResponse(self) + + async def retrieve( + self, + subscription_change_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SubscriptionChangeRetrieveResponse: + """ + This endpoint returns a subscription change given an identifier. + + A subscription change is created by including + `Create-Pending-Subscription-Change: True` in the header of a subscription + mutation API call (e.g. + [create subscription endpoint](/api-reference/subscription/create-subscription), + [schedule plan change endpoint](/api-reference/subscription/schedule-plan-change), + ...). The subscription change will be referenced by the + `pending_subscription_change` field in the response. + + Args: + 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 + """ + if not subscription_change_id: + raise ValueError( + f"Expected a non-empty value for `subscription_change_id` but received {subscription_change_id!r}" + ) + return await self._get( + path_template( + "/subscription_changes/{subscription_change_id}", subscription_change_id=subscription_change_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SubscriptionChangeRetrieveResponse, + ) + + def list( + self, + *, + cursor: Optional[str] | Omit = omit, + customer_id: Optional[str] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + limit: int | Omit = omit, + status: Optional[Literal["pending", "applied", "cancelled"]] | Omit = omit, + # 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, + ) -> AsyncPaginator[SubscriptionChangeListResponse, AsyncPage[SubscriptionChangeListResponse]]: + """This endpoint returns a list of pending subscription changes for a customer. + + Use + the [Fetch Subscription Change](fetch-subscription-change) endpoint to retrieve + the expected subscription state after the pending change is applied. + + Args: + 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. + + 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_api_list( + "/subscription_changes", + page=AsyncPage[SubscriptionChangeListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "cursor": cursor, + "customer_id": customer_id, + "external_customer_id": external_customer_id, + "limit": limit, + "status": status, + }, + subscription_change_list_params.SubscriptionChangeListParams, + ), + ), + model=SubscriptionChangeListResponse, + ) + + async def apply( + self, + subscription_change_id: str, + *, + description: Optional[str] | Omit = omit, + mark_as_paid: Optional[bool] | Omit = omit, + payment_external_id: Optional[str] | Omit = omit, + payment_notes: Optional[str] | Omit = omit, + payment_received_date: Union[str, date, None] | Omit = omit, + previously_collected_amount: Optional[str] | Omit = omit, + # 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, + ) -> SubscriptionChangeApplyResponse: + """Apply a subscription change to perform the intended action. + + If a positive amount + is passed with a request to this endpoint, any eligible invoices that were + created will be issued immediately if they only contain in-advance fees. + + Args: + description: Description to apply to the balance transaction representing this credit. + + mark_as_paid: Mark all pending invoices that are payable as paid. If amount is also provided, + mark as paid and credit the difference to the customer's balance. + + payment_external_id: An optional external ID to associate with the payment. Only applicable when + mark_as_paid is true. + + payment_notes: Optional notes about the payment. Only applicable when mark_as_paid is true. + + payment_received_date: A date string to specify the date the payment was received. Only applicable when + mark_as_paid is true. If not provided, defaults to the current date. + + previously_collected_amount: Amount already collected to apply to the customer's balance. If mark_as_paid is + also provided, credit the difference to the customer's balance. + + 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_change_id: + raise ValueError( + f"Expected a non-empty value for `subscription_change_id` but received {subscription_change_id!r}" + ) + return await self._post( + path_template( + "/subscription_changes/{subscription_change_id}/apply", subscription_change_id=subscription_change_id + ), + body=await async_maybe_transform( + { + "description": description, + "mark_as_paid": mark_as_paid, + "payment_external_id": payment_external_id, + "payment_notes": payment_notes, + "payment_received_date": payment_received_date, + "previously_collected_amount": previously_collected_amount, + }, + subscription_change_apply_params.SubscriptionChangeApplyParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=SubscriptionChangeApplyResponse, + ) + + async def cancel( + self, + subscription_change_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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + idempotency_key: str | None = None, + ) -> SubscriptionChangeCancelResponse: + """Cancel a subscription change. + + The change can no longer be applied. A + subscription can only have one "pending" change at a time - use this endpoint to + cancel an existing change before creating a new one. + + Args: + 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_change_id: + raise ValueError( + f"Expected a non-empty value for `subscription_change_id` but received {subscription_change_id!r}" + ) + return await self._post( + path_template( + "/subscription_changes/{subscription_change_id}/cancel", subscription_change_id=subscription_change_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=SubscriptionChangeCancelResponse, + ) + + +class SubscriptionChangesWithRawResponse: + def __init__(self, subscription_changes: SubscriptionChanges) -> None: + self._subscription_changes = subscription_changes + + self.retrieve = _legacy_response.to_raw_response_wrapper( + subscription_changes.retrieve, + ) + self.list = _legacy_response.to_raw_response_wrapper( + subscription_changes.list, + ) + self.apply = _legacy_response.to_raw_response_wrapper( + subscription_changes.apply, + ) + self.cancel = _legacy_response.to_raw_response_wrapper( + subscription_changes.cancel, + ) + + +class AsyncSubscriptionChangesWithRawResponse: + def __init__(self, subscription_changes: AsyncSubscriptionChanges) -> None: + self._subscription_changes = subscription_changes + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + subscription_changes.retrieve, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + subscription_changes.list, + ) + self.apply = _legacy_response.async_to_raw_response_wrapper( + subscription_changes.apply, + ) + self.cancel = _legacy_response.async_to_raw_response_wrapper( + subscription_changes.cancel, + ) + + +class SubscriptionChangesWithStreamingResponse: + def __init__(self, subscription_changes: SubscriptionChanges) -> None: + self._subscription_changes = subscription_changes + + self.retrieve = to_streamed_response_wrapper( + subscription_changes.retrieve, + ) + self.list = to_streamed_response_wrapper( + subscription_changes.list, + ) + self.apply = to_streamed_response_wrapper( + subscription_changes.apply, + ) + self.cancel = to_streamed_response_wrapper( + subscription_changes.cancel, + ) + + +class AsyncSubscriptionChangesWithStreamingResponse: + def __init__(self, subscription_changes: AsyncSubscriptionChanges) -> None: + self._subscription_changes = subscription_changes + + self.retrieve = async_to_streamed_response_wrapper( + subscription_changes.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + subscription_changes.list, + ) + self.apply = async_to_streamed_response_wrapper( + subscription_changes.apply, + ) + self.cancel = async_to_streamed_response_wrapper( + subscription_changes.cancel, + ) diff --git a/src/orb/resources/subscriptions.py b/src/orb/resources/subscriptions.py index 439361df..59a4a7a6 100644 --- a/src/orb/resources/subscriptions.py +++ b/src/orb/resources/subscriptions.py @@ -10,15 +10,14 @@ from .. import _legacy_response from ..types import ( - Subscription, - SubscriptionUsage, - SubscriptionFetchCostsResponse, - SubscriptionFetchScheduleResponse, subscription_list_params, subscription_cancel_params, subscription_create_params, + subscription_update_params, subscription_fetch_costs_params, subscription_fetch_usage_params, + subscription_update_trial_params, + subscription_redeem_coupon_params, subscription_trigger_phase_params, subscription_fetch_schedule_params, subscription_price_intervals_params, @@ -26,19 +25,19 @@ subscription_update_fixed_fee_quantity_params, subscription_unschedule_fixed_fee_quantity_updates_params, ) -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import ( - maybe_transform, - async_maybe_transform, -) +from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from .._utils import path_template, 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 ..pagination import SyncPage, AsyncPage -from .._base_client import ( - AsyncPaginator, - make_request_options, -) +from .._base_client import AsyncPaginator, make_request_options +from ..types.subscription import Subscription +from ..types.subscription_usage import SubscriptionUsage +from ..types.mutated_subscription import MutatedSubscription +from ..types.subscription_fetch_costs_response import SubscriptionFetchCostsResponse +from ..types.subscription_fetch_schedule_response import SubscriptionFetchScheduleResponse +from ..types.shared_params.billing_cycle_anchor_configuration import BillingCycleAnchorConfiguration __all__ = ["Subscriptions", "AsyncSubscriptions"] @@ -46,43 +45,68 @@ 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 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, *, - align_billing_with_subscription_start_date: bool | NotGiven = NOT_GIVEN, - auto_collection: Optional[bool] | NotGiven = NOT_GIVEN, - aws_region: Optional[str] | NotGiven = NOT_GIVEN, - coupon_redemption_code: Optional[str] | NotGiven = NOT_GIVEN, - credits_overage_rate: Optional[float] | NotGiven = NOT_GIVEN, - customer_id: Optional[str] | NotGiven = NOT_GIVEN, - default_invoice_memo: Optional[str] | NotGiven = NOT_GIVEN, - end_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - 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, - 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[str] | NotGiven = NOT_GIVEN, - plan_id: Optional[str] | NotGiven = NOT_GIVEN, - price_overrides: Optional[Iterable[subscription_create_params.PriceOverride]] | NotGiven = NOT_GIVEN, - start_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + add_adjustments: Optional[Iterable[subscription_create_params.AddAdjustment]] | Omit = omit, + add_prices: Optional[Iterable[subscription_create_params.AddPrice]] | Omit = omit, + align_billing_with_subscription_start_date: bool | Omit = omit, + auto_collection: Optional[bool] | Omit = omit, + auto_issuance: Optional[bool] | Omit = omit, + aws_region: Optional[str] | Omit = omit, + billing_cycle_anchor_configuration: Optional[BillingCycleAnchorConfiguration] | Omit = omit, + coupon_redemption_code: Optional[str] | Omit = omit, + credits_overage_rate: Optional[float] | Omit = omit, + currency: Optional[str] | Omit = omit, + customer_id: Optional[str] | Omit = omit, + default_invoice_memo: Optional[str] | Omit = omit, + end_date: Union[str, datetime, None] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + external_marketplace: Optional[Literal["google", "aws", "azure"]] | Omit = omit, + external_marketplace_reporting_id: Optional[str] | Omit = omit, + external_plan_id: Optional[str] | Omit = omit, + filter: Optional[str] | Omit = omit, + initial_phase_order: Optional[int] | Omit = omit, + invoicing_threshold: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + name: Optional[str] | Omit = omit, + net_terms: Optional[int] | Omit = omit, + per_credit_overage_amount: Optional[float] | Omit = omit, + plan_id: Optional[str] | Omit = omit, + plan_version_number: Optional[int] | Omit = omit, + price_overrides: Optional[Iterable[object]] | Omit = omit, + remove_adjustments: Optional[Iterable[subscription_create_params.RemoveAdjustment]] | Omit = omit, + remove_prices: Optional[Iterable[subscription_create_params.RemovePrice]] | Omit = omit, + replace_adjustments: Optional[Iterable[subscription_create_params.ReplaceAdjustment]] | Omit = omit, + replace_prices: Optional[Iterable[subscription_create_params.ReplacePrice]] | Omit = omit, + start_date: Union[str, datetime, None] | Omit = omit, + trial_duration_days: Optional[int] | Omit = omit, + usage_customer_ids: Optional[SequenceNotStr[str]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """A subscription represents the purchase of a plan by a customer. The customer is @@ -95,7 +119,7 @@ def create( The default configuration for subscriptions in Orb is **In-advance billing** and **Beginning of month alignment** (see - [Subscription](../guides/concepts#subscription) for more details). + [Subscription](/core-concepts##subscription) for more details). In order to change the alignment behavior, Orb also supports billing subscriptions on the day of the month they are created. If @@ -114,265 +138,132 @@ 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 + + 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](/api-reference/price/create-price). See the + [Price resource](/product-catalog/price-configuration) 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](/api-reference/price-interval/add-or-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](/api-reference/price/create-price). See the + [Price resource](/product-catalog/price-configuration) 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](/api-reference/subscription/update-price-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](/api-reference/price-interval/add-or-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" - } - ] - } - ... - } - ``` - - ### 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 - { - ... - "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" - } - ] - } - ... - } - ``` + 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. - ### Matrix pricing + ### Replacing adjustments - 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`. + 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](/api-reference/price-interval/add-or-edit-price-intervals). - ```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" - }, - ... - ] - } - } - ``` + 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) - ### Fixed fees + + Price overrides are being phased out in favor adding/removing/replacing prices. (See + [Customize your customer's subscriptions](/api-reference/subscription/create-subscription)) + - 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](/product-catalog/price-configuration) 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 +310,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: @@ -474,21 +364,95 @@ def create( is hit. To enable threshold billing, pass in an `invoicing_threshold`, which is specified in the subscription's invoicing currency, when creating a subscription. E.g. pass in `10.00` to issue an invoice when usage amounts hit - $10.00 for a subscription that invoices in USD. + \\$$10.00 for a subscription that invoices in USD. + + ## Limits + + By default, Orb limits the number of subscriptions per customer to 100. 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. + + auto_issuance: Used to determine if invoices for this subscription will be automatically + issued. If true, invoices will be automatically issued. If false, invoices will + require manual approval. If `null` is specified, this defaults to the behavior + configured for this customer. + + coupon_redemption_code: Redemption code to be used for this subscription. If the coupon cannot be found + by its redemption code, or cannot be redeemed, an error response will be + returned and the subscription creation or plan change will not be scheduled. + + currency: The currency to use for the subscription. If not specified, the invoicing + currency for the plan will be used. + + default_invoice_memo: Determines the default memo on this subscription's invoices. Note that if this + is not provided, it is determined by the plan configuration. + 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](/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 + be issued for the subscription. If not specified, invoices will only be issued + at the end of the billing period. + 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`. + name: The name to use for the subscription. If not specified, the plan name will be + used. + + net_terms: The net terms determines the difference between the invoice date and the issue + date for the invoice. If you intend the invoice to be due on issue, set this + to 0. If not provided, this defaults to the value specified in the plan. + 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. + + usage_customer_ids: A list of customer IDs whose usage events will be aggregated and billed under + this subscription. By default, a subscription only considers usage events + associated with its attached customer's customer_id. When usage_customer_ids is + provided, the subscription includes usage events from the specified customers + only. Provided usage_customer_ids must be either the customer for this + subscription itself, or any of that customer's children. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -503,11 +467,16 @@ 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, + "auto_issuance": auto_issuance, "aws_region": aws_region, + "billing_cycle_anchor_configuration": billing_cycle_anchor_configuration, "coupon_redemption_code": coupon_redemption_code, "credits_overage_rate": credits_overage_rate, + "currency": currency, "customer_id": customer_id, "default_invoice_memo": default_invoice_memo, "end_date": end_date, @@ -515,14 +484,23 @@ 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, + "name": name, "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, + "usage_customer_ids": usage_customer_ids, }, subscription_create_params.SubscriptionCreateParams, ), @@ -533,36 +511,129 @@ def create( timeout=timeout, idempotency_key=idempotency_key, ), + cast_to=MutatedSubscription, + ) + + def update( + self, + subscription_id: str, + *, + auto_collection: Optional[bool] | Omit = omit, + auto_issuance: Optional[bool] | Omit = omit, + default_invoice_memo: Optional[str] | Omit = omit, + invoicing_threshold: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + net_terms: Optional[int] | Omit = omit, + # 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, + ) -> Subscription: + """ + This endpoint can be used to update the `metadata`, `net terms`, + `auto_collection`, `invoicing_threshold`, and `default_invoice_memo` properties + on a subscription. + + Args: + auto_collection: 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. + + auto_issuance: Used to determine if invoices for this subscription will be automatically + issued. If true, invoices will be automatically issued. If false, invoices will + require manual approval. If `null` is specified, this defaults to the behavior + configured for this customer. + + default_invoice_memo: Determines the default memo on this subscription's invoices. Note that if this + is not provided, it is determined by the plan configuration. + + invoicing_threshold: When this subscription's accrued usage reaches this threshold, an invoice will + be issued for the subscription. If not specified, invoices will only be issued + at the end of the billing period. + + 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`. + + net_terms: 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. + + 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._put( + path_template("/subscriptions/{subscription_id}", subscription_id=subscription_id), + body=maybe_transform( + { + "auto_collection": auto_collection, + "auto_issuance": auto_issuance, + "default_invoice_memo": default_invoice_memo, + "invoicing_threshold": invoicing_threshold, + "metadata": metadata, + "net_terms": net_terms, + }, + subscription_update_params.SubscriptionUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), cast_to=Subscription, ) def list( self, *, - created_at_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - customer_id: Optional[str] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - status: Optional[Literal["active", "ended", "upcoming"]] | NotGiven = NOT_GIVEN, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + cursor: Optional[str] | Omit = omit, + customer_id: Optional[SequenceNotStr[str]] | Omit = omit, + external_customer_id: Optional[SequenceNotStr[str]] | Omit = omit, + external_plan_id: Optional[str] | Omit = omit, + limit: int | Omit = omit, + plan_id: Optional[str] | Omit = omit, + status: Optional[Literal["active", "ended", "upcoming"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[Subscription]: """ This endpoint returns a list of all subscriptions for an account as a - [paginated](../reference/pagination) list, ordered starting from the most + [paginated](/api-reference/pagination) list, ordered starting from the most recently created subscription. For a full discussion of the subscription - resource, see [Subscription](../guides/concepts#subscription). + resource, see [Subscription](/core-concepts##subscription). - Subscriptions can be filtered to a single customer by passing in the - `customer_id` query parameter or the `external_customer_id` query parameter. + Subscriptions can be filtered for a specific customer by using either the + customer_id or external_customer_id query parameters. To filter subscriptions + for multiple customers, use the customer_id[] or external_customer_id[] query + parameters. + + Subscriptions can be filtered by status using the status query parameter (one of + `active`, `ended`, or `upcoming`). To filter for multiple statuses in a single + request, use the status[] query parameter, e.g. + `status[]=active&status[]=ended`. Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -595,7 +666,9 @@ def list( "cursor": cursor, "customer_id": customer_id, "external_customer_id": external_customer_id, + "external_plan_id": external_plan_id, "limit": limit, + "plan_id": plan_id, "status": status, }, subscription_list_params.SubscriptionListParams, @@ -609,15 +682,16 @@ def cancel( subscription_id: str, *, cancel_option: Literal["end_of_subscription_term", "immediate", "requested_date"], - cancellation_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + allow_invoice_credit_or_void: Optional[bool] | Omit = omit, + cancellation_date: Union[str, datetime, None] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """This endpoint can be used to cancel an existing subscription. It returns the @@ -680,11 +754,15 @@ def cancel( current period. If the cancellation is before the most recently issued invoice, Orb will void the intervening invoice and generate a new one based on the new dates for the subscription. See the section on - [cancellation behaviors](../guides/product-catalog/creating-subscriptions.md#cancellation-behaviors). + [cancellation behaviors](/product-catalog/creating-subscriptions#cancellation-behaviors). Args: cancel_option: Determines the timing of subscription cancellation + allow_invoice_credit_or_void: If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + cancellation_date: The date that the cancellation should take effect. This parameter can only be passed if the `cancel_option` is `requested_date`. @@ -701,10 +779,11 @@ def cancel( 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}/cancel", + path_template("/subscriptions/{subscription_id}/cancel", subscription_id=subscription_id), body=maybe_transform( { "cancel_option": cancel_option, + "allow_invoice_credit_or_void": allow_invoice_credit_or_void, "cancellation_date": cancellation_date, }, subscription_cancel_params.SubscriptionCancelParams, @@ -716,7 +795,7 @@ def cancel( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, ) def fetch( @@ -728,10 +807,10 @@ def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Subscription: """ - This endpoint is used to fetch a [Subscription](../guides/concepts#subscription) + This endpoint is used to fetch a [Subscription](/core-concepts##subscription) given an identifier. Args: @@ -746,7 +825,7 @@ def fetch( if not subscription_id: raise ValueError(f"Expected a non-empty value for `subscription_id` but received {subscription_id!r}") return self._get( - f"/subscriptions/{subscription_id}", + path_template("/subscriptions/{subscription_id}", subscription_id=subscription_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -757,15 +836,16 @@ def fetch_costs( self, subscription_id: str, *, - timeframe_end: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - timeframe_start: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - view_mode: Optional[Literal["periodic", "cumulative"]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + timeframe_end: Union[str, datetime, None] | Omit = omit, + timeframe_start: Union[str, datetime, None] | Omit = omit, + view_mode: Optional[Literal["periodic", "cumulative"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SubscriptionFetchCostsResponse: """ This endpoint is used to fetch a day-by-day snapshot of a subscription's costs @@ -774,12 +854,14 @@ def fetch_costs( metric, in usage units rather than a currency). The semantics of this endpoint exactly mirror those of - [fetching a customer's costs](fetch-customer-costs). Use this endpoint to limit - your analysis of costs to a specific subscription for the customer (e.g. to - de-aggregate costs when a customer's subscription has started and stopped on the - same day). + [fetching a customer's costs](/api-reference/customer/fetch-customer-costs). Use + this endpoint to limit your analysis of costs to a specific subscription for the + customer (e.g. to de-aggregate costs when a customer's subscription has started + and stopped on the same day). Args: + currency: The currency or custom pricing unit to use. + timeframe_end: Costs returned are exclusive of `timeframe_end`. timeframe_start: Costs returned are inclusive of `timeframe_start`. @@ -800,7 +882,7 @@ def fetch_costs( if not subscription_id: raise ValueError(f"Expected a non-empty value for `subscription_id` but received {subscription_id!r}") return self._get( - f"/subscriptions/{subscription_id}/costs", + path_template("/subscriptions/{subscription_id}/costs", subscription_id=subscription_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -808,6 +890,7 @@ def fetch_costs( timeout=timeout, query=maybe_transform( { + "currency": currency, "timeframe_end": timeframe_end, "timeframe_start": timeframe_start, "view_mode": view_mode, @@ -822,21 +905,21 @@ def fetch_schedule( self, subscription_id: str, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - start_date_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - start_date_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - start_date_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - start_date_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + start_date_gt: Union[str, datetime, None] | Omit = omit, + start_date_gte: Union[str, datetime, None] | Omit = omit, + start_date_lt: Union[str, datetime, None] | Omit = omit, + start_date_lte: Union[str, datetime, None] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[SubscriptionFetchScheduleResponse]: """ - This endpoint returns a [paginated](../reference/pagination) list of all plans + This endpoint returns a [paginated](/api-reference/pagination) list of all plans associated with a subscription along with their start and end dates. This list contains the subscription's initial plan along with past and future plan changes. @@ -858,7 +941,7 @@ def fetch_schedule( if not subscription_id: raise ValueError(f"Expected a non-empty value for `subscription_id` but received {subscription_id!r}") return self._get_api_list( - f"/subscriptions/{subscription_id}/schedule", + path_template("/subscriptions/{subscription_id}/schedule", subscription_id=subscription_id), page=SyncPage[SubscriptionFetchScheduleResponse], options=make_request_options( extra_headers=extra_headers, @@ -884,24 +967,22 @@ def fetch_usage( self, subscription_id: str, *, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - first_dimension_key: Optional[str] | NotGiven = NOT_GIVEN, - first_dimension_value: Optional[str] | NotGiven = NOT_GIVEN, - granularity: Optional[Literal["day"]] | NotGiven = NOT_GIVEN, - group_by: Optional[str] | NotGiven = NOT_GIVEN, - limit: Optional[int] | NotGiven = NOT_GIVEN, - second_dimension_key: Optional[str] | NotGiven = NOT_GIVEN, - second_dimension_value: Optional[str] | NotGiven = NOT_GIVEN, - timeframe_end: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - timeframe_start: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - view_mode: Optional[Literal["periodic", "cumulative"]] | NotGiven = NOT_GIVEN, + billable_metric_id: Optional[str] | Omit = omit, + first_dimension_key: Optional[str] | Omit = omit, + first_dimension_value: Optional[str] | Omit = omit, + granularity: Optional[Literal["day"]] | Omit = omit, + group_by: Optional[str] | Omit = omit, + second_dimension_key: Optional[str] | Omit = omit, + second_dimension_value: Optional[str] | Omit = omit, + timeframe_end: Union[str, datetime, None] | Omit = omit, + timeframe_start: Union[str, datetime, None] | Omit = omit, + view_mode: Optional[Literal["periodic", "cumulative"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SubscriptionUsage: """This endpoint is used to fetch a subscription's usage in Orb. @@ -1105,16 +1186,10 @@ def fetch_usage( single billable metric. Note that both `group_by` and `billable_metric_id` must be specified together. - cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned - from the initial request. - granularity: This determines the windowing of usage reporting. group_by: Groups per-price usage by the key provided. - limit: If including a `group_by`, the number of groups to fetch data for. Defaults - to 1000. - timeframe_end: Usage returned is exclusive of `timeframe_end`. timeframe_start: Usage returned is inclusive of `timeframe_start`. @@ -1137,7 +1212,7 @@ def fetch_usage( return cast( SubscriptionUsage, self._get( - f"/subscriptions/{subscription_id}/usage", + path_template("/subscriptions/{subscription_id}/usage", subscription_id=subscription_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -1146,12 +1221,10 @@ def fetch_usage( query=maybe_transform( { "billable_metric_id": billable_metric_id, - "cursor": cursor, "first_dimension_key": first_dimension_key, "first_dimension_value": first_dimension_value, "granularity": granularity, "group_by": group_by, - "limit": limit, "second_dimension_key": second_dimension_key, "second_dimension_value": second_dimension_value, "timeframe_end": timeframe_end, @@ -1169,21 +1242,25 @@ def price_intervals( self, subscription_id: str, *, - add: Iterable[subscription_price_intervals_params.Add] | NotGiven = NOT_GIVEN, - edit: Iterable[subscription_price_intervals_params.Edit] | NotGiven = NOT_GIVEN, + add: Iterable[subscription_price_intervals_params.Add] | Omit = omit, + add_adjustments: Iterable[subscription_price_intervals_params.AddAdjustment] | Omit = omit, + allow_invoice_credit_or_void: Optional[bool] | Omit = omit, + can_defer_billing: Optional[bool] | Omit = omit, + edit: Iterable[subscription_price_intervals_params.Edit] | Omit = omit, + edit_adjustments: Iterable[subscription_price_intervals_params.EditAdjustment] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """ This endpoint is used to add and edit subscription - [price intervals](../reference/price-interval). By making modifications to a - subscription’s price intervals, you can - [flexibly and atomically control the billing behavior of a subscription](../guides/product-catalog/modifying-subscriptions). + [price intervals](/api-reference/price-interval/add-or-edit-price-intervals). By + making modifications to a subscription’s price intervals, you can + [flexibly and atomically control the billing behavior of a subscription](/product-catalog/modifying-subscriptions). ## Adding price intervals @@ -1206,6 +1283,21 @@ def price_intervals( interval. This will only apply to this price interval, not any other price intervals on the subscription. + ## Adjustment intervals + + An adjustment interval represents the time period that a particular adjustment + (a discount, minimum, or maximum) applies to the prices on a subscription. + Adjustment intervals can be added to a subscription by specifying them in the + `add_adjustments` array, or modified via the `edit_adjustments` array. When + creating an adjustment interval, you'll need to provide the definition of the + new adjustment (the type of adjustment, and which prices it applies to), as well + as the start and end dates for the adjustment interval. The start and end dates + of an existing adjustment interval can be edited via the `edit_adjustments` + field (just like price intervals). (To "change" the amount of a discount, + minimum, or maximum, then, you'll need to end the existing interval, and create + a new adjustment interval with the new amount and a start date that matches the + end date of the previous interval.) + ## Editing price intervals Price intervals can be adjusted by specifying edits to make in the `edit` array. @@ -1241,8 +1333,19 @@ def price_intervals( Args: add: A list of price intervals to add to the subscription. + add_adjustments: A list of adjustments to add to the subscription. + + allow_invoice_credit_or_void: If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + + can_defer_billing: If set, the default value to use for added/edited price intervals with an + end_date set. + edit: A list of price intervals to edit on the subscription. + edit_adjustments: A list of adjustments to edit on the subscription. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1256,11 +1359,15 @@ def price_intervals( 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}/price_intervals", + path_template("/subscriptions/{subscription_id}/price_intervals", subscription_id=subscription_id), body=maybe_transform( { "add": add, + "add_adjustments": add_adjustments, + "allow_invoice_credit_or_void": allow_invoice_credit_or_void, + "can_defer_billing": can_defer_billing, "edit": edit, + "edit_adjustments": edit_adjustments, }, subscription_price_intervals_params.SubscriptionPriceIntervalsParams, ), @@ -1271,7 +1378,73 @@ def price_intervals( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, + ) + + def redeem_coupon( + self, + subscription_id: str, + *, + change_option: Literal["requested_date", "end_of_subscription_term", "immediate"], + allow_invoice_credit_or_void: Optional[bool] | Omit = omit, + change_date: Union[str, datetime, None] | Omit = omit, + coupon_id: Optional[str] | Omit = omit, + coupon_redemption_code: Optional[str] | Omit = omit, + # 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, + ) -> MutatedSubscription: + """ + Redeem a coupon effective at a given time. + + Args: + allow_invoice_credit_or_void: If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + + change_date: The date that the coupon discount should take effect. This parameter can only be + passed if the `change_option` is `requested_date`. + + coupon_id: Coupon ID to be redeemed for this subscription. + + coupon_redemption_code: Redemption code of the coupon to be redeemed for this subscription. + + 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( + path_template("/subscriptions/{subscription_id}/redeem_coupon", subscription_id=subscription_id), + body=maybe_transform( + { + "change_option": change_option, + "allow_invoice_credit_or_void": allow_invoice_credit_or_void, + "change_date": change_date, + "coupon_id": coupon_id, + "coupon_redemption_code": coupon_redemption_code, + }, + subscription_redeem_coupon_params.SubscriptionRedeemCouponParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=MutatedSubscription, ) def schedule_plan_change( @@ -1279,98 +1452,311 @@ def schedule_plan_change( subscription_id: str, *, change_option: Literal["requested_date", "end_of_subscription_term", "immediate"], - align_billing_with_plan_change_date: Optional[bool] | NotGiven = NOT_GIVEN, - billing_cycle_alignment: Optional[Literal["unchanged", "plan_change_date", "start_of_month"]] - | NotGiven = NOT_GIVEN, - change_date: Optional[str] | NotGiven = NOT_GIVEN, - coupon_redemption_code: Optional[str] | NotGiven = NOT_GIVEN, - credits_overage_rate: Optional[float] | NotGiven = NOT_GIVEN, - external_plan_id: Optional[str] | NotGiven = NOT_GIVEN, - initial_phase_order: Optional[int] | NotGiven = NOT_GIVEN, - invoicing_threshold: Optional[str] | NotGiven = NOT_GIVEN, - per_credit_overage_amount: Optional[str] | NotGiven = NOT_GIVEN, - plan_id: Optional[str] | NotGiven = NOT_GIVEN, - price_overrides: Optional[Iterable[subscription_schedule_plan_change_params.PriceOverride]] - | NotGiven = NOT_GIVEN, + add_adjustments: Optional[Iterable[subscription_schedule_plan_change_params.AddAdjustment]] | Omit = omit, + add_prices: Optional[Iterable[subscription_schedule_plan_change_params.AddPrice]] | Omit = omit, + align_billing_with_plan_change_date: Optional[bool] | Omit = omit, + auto_collection: Optional[bool] | Omit = omit, + auto_issuance: Optional[bool] | Omit = omit, + billing_cycle_alignment: Optional[Literal["unchanged", "plan_change_date", "start_of_month"]] | Omit = omit, + billing_cycle_anchor_configuration: Optional[BillingCycleAnchorConfiguration] | Omit = omit, + change_date: Union[str, datetime, None] | Omit = omit, + coupon_redemption_code: Optional[str] | Omit = omit, + credits_overage_rate: Optional[float] | Omit = omit, + default_invoice_memo: Optional[str] | Omit = omit, + external_plan_id: Optional[str] | Omit = omit, + filter: Optional[str] | Omit = omit, + initial_phase_order: Optional[int] | Omit = omit, + invoicing_threshold: Optional[str] | Omit = omit, + net_terms: Optional[int] | Omit = omit, + per_credit_overage_amount: Optional[float] | Omit = omit, + plan_id: Optional[str] | Omit = omit, + plan_version_number: Optional[int] | Omit = omit, + price_overrides: Optional[Iterable[object]] | Omit = omit, + remove_adjustments: Optional[Iterable[subscription_schedule_plan_change_params.RemoveAdjustment]] | Omit = omit, + remove_prices: Optional[Iterable[subscription_schedule_plan_change_params.RemovePrice]] | Omit = omit, + replace_adjustments: Optional[Iterable[subscription_schedule_plan_change_params.ReplaceAdjustment]] + | Omit = omit, + replace_prices: Optional[Iterable[subscription_schedule_plan_change_params.ReplacePrice]] | Omit = omit, + trial_duration_days: Optional[int] | Omit = omit, + usage_customer_ids: Optional[SequenceNotStr[str]] | Omit = omit, # 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, + 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. + ) -> MutatedSubscription: + """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 occurs. 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. + + + 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](/api-reference/price/create-price). See the + [Price resource](/product-catalog/price-configuration) 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`. If `start_date` is unspecified, the start of the phase / plan change + time will be used. If `end_date` is unspecified, it will finish at the end of + the phase / have no end time. + + 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](/api-reference/price/create-price). See the + [Price resource](/product-catalog/price-configuration) 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](/api-reference/subscription/update-price-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](/api-reference/price-interval/add-or-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 `start_date` is unspecified, the start of the phase / plan change + time will be used. If `end_date` is unspecified, it will finish at the end of + the phase / have no end time. + + ### 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](/api-reference/price-interval/add-or-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) + + + Price overrides are being phased out in favor adding/removing/replacing prices. (See + [Customize your customer's subscriptions](/api-reference/subscription/schedule-plan-change)) + + + 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](/product-catalog/price-configuration) 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 + + When scheduling multiple plan changes with the same date, the latest plan change + on that day takes effect. ## Prorations for in-advance fees By default, Orb calculates the prorated difference in any fixed fees when making a plan change, adjusting the customer balance as needed. For details on this behavior, see - [Modifying subscriptions](../guides/product-catalog/modifying-subscriptions.md#prorations-for-in-advance-fees). + [Modifying subscriptions](/product-catalog/modifying-subscriptions#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. + aligned with the plan change's effective date. + + 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. + + auto_issuance: Used to determine if invoices for this subscription will be automatically + issued. If true, invoices will be automatically issued. If false, invoices will + require manual approval. If `null` is specified, this defaults to the behavior + configured for this customer. - billing_cycle_alignment: Reset billing periods to be aligned with the plan change’s effective date or + billing_cycle_alignment: Reset billing periods to be aligned with the plan change's effective date or start of the month. Defaults to `unchanged` which keeps subscription's existing billing cycle alignment. change_date: The date that the plan change should take effect. This parameter can only be - passed if the `change_option` is `requested_date`. + passed if the `change_option` is `requested_date`. If a date with no time is + passed, the plan change will happen at midnight in the customer's timezone. coupon_redemption_code: Redemption code to be used for this subscription. If the coupon cannot be found by its redemption code, or cannot be redeemed, an error response will be - returned and the plan change will not be scheduled. + returned and the subscription creation or plan change will not be scheduled. + + default_invoice_memo: Determines the default memo on this subscription's invoices. Note that if this + is not provided, it is determined by the plan configuration. 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](/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 be issued for the subscription. If not specified, invoices will only be issued at the end of the billing period. + net_terms: The net terms determines the difference between the invoice date and the issue + date for the invoice. If you intend the invoice to be due on issue, set this + to 0. If not provided, this defaults to the value specified in the plan. + 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. + + usage_customer_ids: A list of customer IDs whose usage events will be aggregated and billed under + this subscription. By default, a subscription only considers usage events + associated with its attached customer's customer_id. When usage_customer_ids is + provided, the subscription includes usage events from the specified customers + only. Provided usage_customer_ids must be either the customer for this + subscription itself, or any of that customer's children. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1384,21 +1770,36 @@ def schedule_plan_change( 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}/schedule_plan_change", + path_template("/subscriptions/{subscription_id}/schedule_plan_change", subscription_id=subscription_id), 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, + "auto_issuance": auto_issuance, "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, + "usage_customer_ids": usage_customer_ids, }, subscription_schedule_plan_change_params.SubscriptionSchedulePlanChangeParams, ), @@ -1409,27 +1810,32 @@ def schedule_plan_change( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, ) def trigger_phase( self, subscription_id: str, *, - effective_date: Union[str, date, None] | NotGiven = NOT_GIVEN, + allow_invoice_credit_or_void: Optional[bool] | Omit = omit, + effective_date: Union[str, date, None] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """ Manually trigger a phase, effective the given date (or the current time, if not specified). Args: + allow_invoice_credit_or_void: If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + effective_date: The date on which the phase change should take effect. If not provided, defaults to today in the customer's timezone. @@ -1446,9 +1852,13 @@ def trigger_phase( 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}/trigger_phase", + path_template("/subscriptions/{subscription_id}/trigger_phase", subscription_id=subscription_id), body=maybe_transform( - {"effective_date": effective_date}, subscription_trigger_phase_params.SubscriptionTriggerPhaseParams + { + "allow_invoice_credit_or_void": allow_invoice_credit_or_void, + "effective_date": effective_date, + }, + subscription_trigger_phase_params.SubscriptionTriggerPhaseParams, ), options=make_request_options( extra_headers=extra_headers, @@ -1457,7 +1867,7 @@ def trigger_phase( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, ) def unschedule_cancellation( @@ -1469,9 +1879,9 @@ def unschedule_cancellation( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """ This endpoint can be used to unschedule any pending cancellations for a subscription. @@ -1480,6 +1890,12 @@ def unschedule_cancellation( cancellation. This operation will turn on auto-renew, ensuring that the subscription does not end at the currently scheduled cancellation time. + Note: uncancellation is a lossy operation. Price intervals that were cut short + by the cancellation are extended to infinity (original end dates are lost), and + future intervals or phases scheduled after the cancellation time are permanently + deleted. For complex subscriptions with phases or scheduled plan changes, + consider creating a new plan change instead of uncancelling. + Args: extra_headers: Send extra headers @@ -1494,7 +1910,7 @@ def unschedule_cancellation( 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}/unschedule_cancellation", + path_template("/subscriptions/{subscription_id}/unschedule_cancellation", subscription_id=subscription_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -1502,7 +1918,7 @@ def unschedule_cancellation( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, ) def unschedule_fixed_fee_quantity_updates( @@ -1515,14 +1931,15 @@ def unschedule_fixed_fee_quantity_updates( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """ This endpoint can be used to clear scheduled updates to the quantity for a fixed fee. - If there are no updates scheduled, this endpoint is a no-op. + If there are no updates scheduled, a request validation error will be returned + with a 400 status code. Args: price_id: Price for which the updates should be cleared. Must be a fixed fee. @@ -1540,7 +1957,10 @@ def unschedule_fixed_fee_quantity_updates( 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}/unschedule_fixed_fee_quantity_updates", + path_template( + "/subscriptions/{subscription_id}/unschedule_fixed_fee_quantity_updates", + subscription_id=subscription_id, + ), body=maybe_transform( {"price_id": price_id}, subscription_unschedule_fixed_fee_quantity_updates_params.SubscriptionUnscheduleFixedFeeQuantityUpdatesParams, @@ -1552,7 +1972,7 @@ def unschedule_fixed_fee_quantity_updates( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, ) def unschedule_pending_plan_changes( @@ -1564,12 +1984,12 @@ def unschedule_pending_plan_changes( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """ This endpoint can be used to unschedule any pending plan changes on an existing - subscription. + subscription. When called, all upcoming plan changes will be unscheduled. Args: extra_headers: Send extra headers @@ -1585,7 +2005,9 @@ def unschedule_pending_plan_changes( 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}/unschedule_pending_plan_changes", + path_template( + "/subscriptions/{subscription_id}/unschedule_pending_plan_changes", subscription_id=subscription_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -1593,7 +2015,7 @@ def unschedule_pending_plan_changes( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, ) def update_fixed_fee_quantity( @@ -1602,16 +2024,17 @@ def update_fixed_fee_quantity( *, price_id: str, quantity: float, - change_option: Literal["immediate", "upcoming_invoice", "effective_date"] | NotGiven = NOT_GIVEN, - effective_date: Union[str, date, None] | NotGiven = NOT_GIVEN, + allow_invoice_credit_or_void: Optional[bool] | Omit = omit, + change_option: Literal["immediate", "upcoming_invoice", "effective_date"] | Omit = omit, + effective_date: Union[str, date, None] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """ This endpoint can be used to update the quantity for a fixed fee. @@ -1631,12 +2054,16 @@ def update_fixed_fee_quantity( Args: price_id: Price for which the quantity should be updated. Must be a fixed fee. + allow_invoice_credit_or_void: If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + change_option: Determines when the change takes effect. Note that if `effective_date` is specified, this defaults to `effective_date`. Otherwise, this defaults to - `immediate` unless it's explicitly set to `upcoming_invoice. + `immediate` unless it's explicitly set to `upcoming_invoice`. effective_date: The date that the quantity change should take effect, localized to the - customer's timezone. Ifthis parameter is not passed in, the quantity change is + customer's timezone. If this parameter is not passed in, the quantity change is effective according to `change_option`. extra_headers: Send extra headers @@ -1652,11 +2079,14 @@ def update_fixed_fee_quantity( 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_fixed_fee_quantity", + path_template( + "/subscriptions/{subscription_id}/update_fixed_fee_quantity", subscription_id=subscription_id + ), body=maybe_transform( { "price_id": price_id, "quantity": quantity, + "allow_invoice_credit_or_void": allow_invoice_credit_or_void, "change_option": change_option, "effective_date": effective_date, }, @@ -1669,50 +2099,148 @@ def update_fixed_fee_quantity( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, + ) + + def update_trial( + self, + subscription_id: str, + *, + trial_end_date: Union[Union[str, datetime], Literal["immediate"]], + shift: bool | Omit = omit, + # 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, + ) -> MutatedSubscription: + """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( + path_template("/subscriptions/{subscription_id}/update_trial", subscription_id=subscription_id), + 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=MutatedSubscription, ) 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 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, *, - align_billing_with_subscription_start_date: bool | NotGiven = NOT_GIVEN, - auto_collection: Optional[bool] | NotGiven = NOT_GIVEN, - aws_region: Optional[str] | NotGiven = NOT_GIVEN, - coupon_redemption_code: Optional[str] | NotGiven = NOT_GIVEN, - credits_overage_rate: Optional[float] | NotGiven = NOT_GIVEN, - customer_id: Optional[str] | NotGiven = NOT_GIVEN, - default_invoice_memo: Optional[str] | NotGiven = NOT_GIVEN, - end_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - 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, - 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[str] | NotGiven = NOT_GIVEN, - plan_id: Optional[str] | NotGiven = NOT_GIVEN, - price_overrides: Optional[Iterable[subscription_create_params.PriceOverride]] | NotGiven = NOT_GIVEN, - start_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + add_adjustments: Optional[Iterable[subscription_create_params.AddAdjustment]] | Omit = omit, + add_prices: Optional[Iterable[subscription_create_params.AddPrice]] | Omit = omit, + align_billing_with_subscription_start_date: bool | Omit = omit, + auto_collection: Optional[bool] | Omit = omit, + auto_issuance: Optional[bool] | Omit = omit, + aws_region: Optional[str] | Omit = omit, + billing_cycle_anchor_configuration: Optional[BillingCycleAnchorConfiguration] | Omit = omit, + coupon_redemption_code: Optional[str] | Omit = omit, + credits_overage_rate: Optional[float] | Omit = omit, + currency: Optional[str] | Omit = omit, + customer_id: Optional[str] | Omit = omit, + default_invoice_memo: Optional[str] | Omit = omit, + end_date: Union[str, datetime, None] | Omit = omit, + external_customer_id: Optional[str] | Omit = omit, + external_marketplace: Optional[Literal["google", "aws", "azure"]] | Omit = omit, + external_marketplace_reporting_id: Optional[str] | Omit = omit, + external_plan_id: Optional[str] | Omit = omit, + filter: Optional[str] | Omit = omit, + initial_phase_order: Optional[int] | Omit = omit, + invoicing_threshold: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + name: Optional[str] | Omit = omit, + net_terms: Optional[int] | Omit = omit, + per_credit_overage_amount: Optional[float] | Omit = omit, + plan_id: Optional[str] | Omit = omit, + plan_version_number: Optional[int] | Omit = omit, + price_overrides: Optional[Iterable[object]] | Omit = omit, + remove_adjustments: Optional[Iterable[subscription_create_params.RemoveAdjustment]] | Omit = omit, + remove_prices: Optional[Iterable[subscription_create_params.RemovePrice]] | Omit = omit, + replace_adjustments: Optional[Iterable[subscription_create_params.ReplaceAdjustment]] | Omit = omit, + replace_prices: Optional[Iterable[subscription_create_params.ReplacePrice]] | Omit = omit, + start_date: Union[str, datetime, None] | Omit = omit, + trial_duration_days: Optional[int] | Omit = omit, + usage_customer_ids: Optional[SequenceNotStr[str]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """A subscription represents the purchase of a plan by a customer. The customer is @@ -1725,7 +2253,7 @@ async def create( The default configuration for subscriptions in Orb is **In-advance billing** and **Beginning of month alignment** (see - [Subscription](../guides/concepts#subscription) for more details). + [Subscription](/core-concepts##subscription) for more details). In order to change the alignment behavior, Orb also supports billing subscriptions on the day of the month they are created. If @@ -1744,265 +2272,132 @@ 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 + + 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](/api-reference/price/create-price). See the + [Price resource](/product-catalog/price-configuration) 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](/api-reference/price-interval/add-or-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](/api-reference/price/create-price). See the + [Price resource](/product-catalog/price-configuration) 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" - } - ] - } - ... - } - ``` - - ### 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 - { - ... - "id": "price_id", - "model_type": "package", - "package_config": { - "package_amount": "0.80", - "package_size": 10 - } - ... - } - ``` + 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](/api-reference/subscription/update-price-quantity) + endpoint. - ### BPS pricing + The replacement price will have the same phase, if applicable, and the same + start and end dates as the price it replaces. - 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. + 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": "bps", - "bps_config": { - "bps": 125, - "per_event_cap": "11.00" - } - ... - } - ``` + 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. - ### Bulk BPS pricing + ### Adding adjustments - 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. + 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](/api-reference/price-interval/add-or-edit-price-intervals). - ```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" - } - ] - } - ... - } - ``` + 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. - ### Tiered 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. - 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. + ### Removing adjustments - ```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" - } - ] - } - ... - } - ``` + 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. - ### Matrix pricing + ### Replacing adjustments - 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`. + 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](/api-reference/price-interval/add-or-edit-price-intervals). - ```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" - }, - ... - ] - } - } - ``` + 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) - ### Fixed fees + + Price overrides are being phased out in favor adding/removing/replacing prices. (See + [Customize your customer's subscriptions](/api-reference/subscription/create-subscription)) + - 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](/product-catalog/price-configuration) 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 @@ -2049,13 +2444,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: @@ -2104,21 +2498,95 @@ async def create( is hit. To enable threshold billing, pass in an `invoicing_threshold`, which is specified in the subscription's invoicing currency, when creating a subscription. E.g. pass in `10.00` to issue an invoice when usage amounts hit - $10.00 for a subscription that invoices in USD. + \\$$10.00 for a subscription that invoices in USD. + + ## Limits + + By default, Orb limits the number of subscriptions per customer to 100. 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. + + auto_issuance: Used to determine if invoices for this subscription will be automatically + issued. If true, invoices will be automatically issued. If false, invoices will + require manual approval. If `null` is specified, this defaults to the behavior + configured for this customer. + + coupon_redemption_code: Redemption code to be used for this subscription. If the coupon cannot be found + by its redemption code, or cannot be redeemed, an error response will be + returned and the subscription creation or plan change will not be scheduled. + + currency: The currency to use for the subscription. If not specified, the invoicing + currency for the plan will be used. + + default_invoice_memo: Determines the default memo on this subscription's invoices. Note that if this + is not provided, it is determined by the plan configuration. + 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](/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 + be issued for the subscription. If not specified, invoices will only be issued + at the end of the billing period. + 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`. + name: The name to use for the subscription. If not specified, the plan name will be + used. + + net_terms: The net terms determines the difference between the invoice date and the issue + date for the invoice. If you intend the invoice to be due on issue, set this + to 0. If not provided, this defaults to the value specified in the plan. + 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. + + usage_customer_ids: A list of customer IDs whose usage events will be aggregated and billed under + this subscription. By default, a subscription only considers usage events + associated with its attached customer's customer_id. When usage_customer_ids is + provided, the subscription includes usage events from the specified customers + only. Provided usage_customer_ids must be either the customer for this + subscription itself, or any of that customer's children. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -2133,11 +2601,16 @@ 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, + "auto_issuance": auto_issuance, "aws_region": aws_region, + "billing_cycle_anchor_configuration": billing_cycle_anchor_configuration, "coupon_redemption_code": coupon_redemption_code, "credits_overage_rate": credits_overage_rate, + "currency": currency, "customer_id": customer_id, "default_invoice_memo": default_invoice_memo, "end_date": end_date, @@ -2145,14 +2618,23 @@ 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, + "name": name, "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, + "usage_customer_ids": usage_customer_ids, }, subscription_create_params.SubscriptionCreateParams, ), @@ -2163,36 +2645,129 @@ async def create( timeout=timeout, idempotency_key=idempotency_key, ), + cast_to=MutatedSubscription, + ) + + async def update( + self, + subscription_id: str, + *, + auto_collection: Optional[bool] | Omit = omit, + auto_issuance: Optional[bool] | Omit = omit, + default_invoice_memo: Optional[str] | Omit = omit, + invoicing_threshold: Optional[str] | Omit = omit, + metadata: Optional[Dict[str, Optional[str]]] | Omit = omit, + net_terms: Optional[int] | Omit = omit, + # 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, + ) -> Subscription: + """ + This endpoint can be used to update the `metadata`, `net terms`, + `auto_collection`, `invoicing_threshold`, and `default_invoice_memo` properties + on a subscription. + + Args: + auto_collection: 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. + + auto_issuance: Used to determine if invoices for this subscription will be automatically + issued. If true, invoices will be automatically issued. If false, invoices will + require manual approval. If `null` is specified, this defaults to the behavior + configured for this customer. + + default_invoice_memo: Determines the default memo on this subscription's invoices. Note that if this + is not provided, it is determined by the plan configuration. + + invoicing_threshold: When this subscription's accrued usage reaches this threshold, an invoice will + be issued for the subscription. If not specified, invoices will only be issued + at the end of the billing period. + + 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`. + + net_terms: 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. + + 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._put( + path_template("/subscriptions/{subscription_id}", subscription_id=subscription_id), + body=await async_maybe_transform( + { + "auto_collection": auto_collection, + "auto_issuance": auto_issuance, + "default_invoice_memo": default_invoice_memo, + "invoicing_threshold": invoicing_threshold, + "metadata": metadata, + "net_terms": net_terms, + }, + subscription_update_params.SubscriptionUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), cast_to=Subscription, ) def list( self, *, - created_at_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - created_at_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - customer_id: Optional[str] | NotGiven = NOT_GIVEN, - external_customer_id: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - status: Optional[Literal["active", "ended", "upcoming"]] | NotGiven = NOT_GIVEN, + created_at_gt: Union[str, datetime, None] | Omit = omit, + created_at_gte: Union[str, datetime, None] | Omit = omit, + created_at_lt: Union[str, datetime, None] | Omit = omit, + created_at_lte: Union[str, datetime, None] | Omit = omit, + cursor: Optional[str] | Omit = omit, + customer_id: Optional[SequenceNotStr[str]] | Omit = omit, + external_customer_id: Optional[SequenceNotStr[str]] | Omit = omit, + external_plan_id: Optional[str] | Omit = omit, + limit: int | Omit = omit, + plan_id: Optional[str] | Omit = omit, + status: Optional[Literal["active", "ended", "upcoming"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Subscription, AsyncPage[Subscription]]: """ This endpoint returns a list of all subscriptions for an account as a - [paginated](../reference/pagination) list, ordered starting from the most + [paginated](/api-reference/pagination) list, ordered starting from the most recently created subscription. For a full discussion of the subscription - resource, see [Subscription](../guides/concepts#subscription). + resource, see [Subscription](/core-concepts##subscription). - Subscriptions can be filtered to a single customer by passing in the - `customer_id` query parameter or the `external_customer_id` query parameter. + Subscriptions can be filtered for a specific customer by using either the + customer_id or external_customer_id query parameters. To filter subscriptions + for multiple customers, use the customer_id[] or external_customer_id[] query + parameters. + + Subscriptions can be filtered by status using the status query parameter (one of + `active`, `ended`, or `upcoming`). To filter for multiple statuses in a single + request, use the status[] query parameter, e.g. + `status[]=active&status[]=ended`. Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -2225,7 +2800,9 @@ def list( "cursor": cursor, "customer_id": customer_id, "external_customer_id": external_customer_id, + "external_plan_id": external_plan_id, "limit": limit, + "plan_id": plan_id, "status": status, }, subscription_list_params.SubscriptionListParams, @@ -2239,15 +2816,16 @@ async def cancel( subscription_id: str, *, cancel_option: Literal["end_of_subscription_term", "immediate", "requested_date"], - cancellation_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + allow_invoice_credit_or_void: Optional[bool] | Omit = omit, + cancellation_date: Union[str, datetime, None] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """This endpoint can be used to cancel an existing subscription. It returns the @@ -2310,11 +2888,15 @@ async def cancel( current period. If the cancellation is before the most recently issued invoice, Orb will void the intervening invoice and generate a new one based on the new dates for the subscription. See the section on - [cancellation behaviors](../guides/product-catalog/creating-subscriptions.md#cancellation-behaviors). + [cancellation behaviors](/product-catalog/creating-subscriptions#cancellation-behaviors). Args: cancel_option: Determines the timing of subscription cancellation + allow_invoice_credit_or_void: If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + cancellation_date: The date that the cancellation should take effect. This parameter can only be passed if the `cancel_option` is `requested_date`. @@ -2331,10 +2913,11 @@ async def cancel( 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}/cancel", + path_template("/subscriptions/{subscription_id}/cancel", subscription_id=subscription_id), body=await async_maybe_transform( { "cancel_option": cancel_option, + "allow_invoice_credit_or_void": allow_invoice_credit_or_void, "cancellation_date": cancellation_date, }, subscription_cancel_params.SubscriptionCancelParams, @@ -2346,7 +2929,7 @@ async def cancel( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, ) async def fetch( @@ -2358,10 +2941,10 @@ async def fetch( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Subscription: """ - This endpoint is used to fetch a [Subscription](../guides/concepts#subscription) + This endpoint is used to fetch a [Subscription](/core-concepts##subscription) given an identifier. Args: @@ -2376,7 +2959,7 @@ async def fetch( if not subscription_id: raise ValueError(f"Expected a non-empty value for `subscription_id` but received {subscription_id!r}") return await self._get( - f"/subscriptions/{subscription_id}", + path_template("/subscriptions/{subscription_id}", subscription_id=subscription_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -2387,15 +2970,16 @@ async def fetch_costs( self, subscription_id: str, *, - timeframe_end: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - timeframe_start: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - view_mode: Optional[Literal["periodic", "cumulative"]] | NotGiven = NOT_GIVEN, + currency: Optional[str] | Omit = omit, + timeframe_end: Union[str, datetime, None] | Omit = omit, + timeframe_start: Union[str, datetime, None] | Omit = omit, + view_mode: Optional[Literal["periodic", "cumulative"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SubscriptionFetchCostsResponse: """ This endpoint is used to fetch a day-by-day snapshot of a subscription's costs @@ -2404,12 +2988,14 @@ async def fetch_costs( metric, in usage units rather than a currency). The semantics of this endpoint exactly mirror those of - [fetching a customer's costs](fetch-customer-costs). Use this endpoint to limit - your analysis of costs to a specific subscription for the customer (e.g. to - de-aggregate costs when a customer's subscription has started and stopped on the - same day). + [fetching a customer's costs](/api-reference/customer/fetch-customer-costs). Use + this endpoint to limit your analysis of costs to a specific subscription for the + customer (e.g. to de-aggregate costs when a customer's subscription has started + and stopped on the same day). Args: + currency: The currency or custom pricing unit to use. + timeframe_end: Costs returned are exclusive of `timeframe_end`. timeframe_start: Costs returned are inclusive of `timeframe_start`. @@ -2430,7 +3016,7 @@ async def fetch_costs( if not subscription_id: raise ValueError(f"Expected a non-empty value for `subscription_id` but received {subscription_id!r}") return await self._get( - f"/subscriptions/{subscription_id}/costs", + path_template("/subscriptions/{subscription_id}/costs", subscription_id=subscription_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -2438,6 +3024,7 @@ async def fetch_costs( timeout=timeout, query=await async_maybe_transform( { + "currency": currency, "timeframe_end": timeframe_end, "timeframe_start": timeframe_start, "view_mode": view_mode, @@ -2452,21 +3039,21 @@ def fetch_schedule( self, subscription_id: str, *, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - start_date_gt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - start_date_gte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - start_date_lt: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - start_date_lte: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + cursor: Optional[str] | Omit = omit, + limit: int | Omit = omit, + start_date_gt: Union[str, datetime, None] | Omit = omit, + start_date_gte: Union[str, datetime, None] | Omit = omit, + start_date_lt: Union[str, datetime, None] | Omit = omit, + start_date_lte: Union[str, datetime, None] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[SubscriptionFetchScheduleResponse, AsyncPage[SubscriptionFetchScheduleResponse]]: """ - This endpoint returns a [paginated](../reference/pagination) list of all plans + This endpoint returns a [paginated](/api-reference/pagination) list of all plans associated with a subscription along with their start and end dates. This list contains the subscription's initial plan along with past and future plan changes. @@ -2488,7 +3075,7 @@ def fetch_schedule( if not subscription_id: raise ValueError(f"Expected a non-empty value for `subscription_id` but received {subscription_id!r}") return self._get_api_list( - f"/subscriptions/{subscription_id}/schedule", + path_template("/subscriptions/{subscription_id}/schedule", subscription_id=subscription_id), page=AsyncPage[SubscriptionFetchScheduleResponse], options=make_request_options( extra_headers=extra_headers, @@ -2514,24 +3101,22 @@ async def fetch_usage( self, subscription_id: str, *, - billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, - cursor: Optional[str] | NotGiven = NOT_GIVEN, - first_dimension_key: Optional[str] | NotGiven = NOT_GIVEN, - first_dimension_value: Optional[str] | NotGiven = NOT_GIVEN, - granularity: Optional[Literal["day"]] | NotGiven = NOT_GIVEN, - group_by: Optional[str] | NotGiven = NOT_GIVEN, - limit: Optional[int] | NotGiven = NOT_GIVEN, - second_dimension_key: Optional[str] | NotGiven = NOT_GIVEN, - second_dimension_value: Optional[str] | NotGiven = NOT_GIVEN, - timeframe_end: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - timeframe_start: Union[str, datetime, None] | NotGiven = NOT_GIVEN, - view_mode: Optional[Literal["periodic", "cumulative"]] | NotGiven = NOT_GIVEN, + billable_metric_id: Optional[str] | Omit = omit, + first_dimension_key: Optional[str] | Omit = omit, + first_dimension_value: Optional[str] | Omit = omit, + granularity: Optional[Literal["day"]] | Omit = omit, + group_by: Optional[str] | Omit = omit, + second_dimension_key: Optional[str] | Omit = omit, + second_dimension_value: Optional[str] | Omit = omit, + timeframe_end: Union[str, datetime, None] | Omit = omit, + timeframe_start: Union[str, datetime, None] | Omit = omit, + view_mode: Optional[Literal["periodic", "cumulative"]] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SubscriptionUsage: """This endpoint is used to fetch a subscription's usage in Orb. @@ -2735,16 +3320,10 @@ async def fetch_usage( single billable metric. Note that both `group_by` and `billable_metric_id` must be specified together. - cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned - from the initial request. - granularity: This determines the windowing of usage reporting. group_by: Groups per-price usage by the key provided. - limit: If including a `group_by`, the number of groups to fetch data for. Defaults - to 1000. - timeframe_end: Usage returned is exclusive of `timeframe_end`. timeframe_start: Usage returned is inclusive of `timeframe_start`. @@ -2767,7 +3346,7 @@ async def fetch_usage( return cast( SubscriptionUsage, await self._get( - f"/subscriptions/{subscription_id}/usage", + path_template("/subscriptions/{subscription_id}/usage", subscription_id=subscription_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -2776,12 +3355,10 @@ async def fetch_usage( query=await async_maybe_transform( { "billable_metric_id": billable_metric_id, - "cursor": cursor, "first_dimension_key": first_dimension_key, "first_dimension_value": first_dimension_value, "granularity": granularity, "group_by": group_by, - "limit": limit, "second_dimension_key": second_dimension_key, "second_dimension_value": second_dimension_value, "timeframe_end": timeframe_end, @@ -2799,21 +3376,25 @@ async def price_intervals( self, subscription_id: str, *, - add: Iterable[subscription_price_intervals_params.Add] | NotGiven = NOT_GIVEN, - edit: Iterable[subscription_price_intervals_params.Edit] | NotGiven = NOT_GIVEN, + add: Iterable[subscription_price_intervals_params.Add] | Omit = omit, + add_adjustments: Iterable[subscription_price_intervals_params.AddAdjustment] | Omit = omit, + allow_invoice_credit_or_void: Optional[bool] | Omit = omit, + can_defer_billing: Optional[bool] | Omit = omit, + edit: Iterable[subscription_price_intervals_params.Edit] | Omit = omit, + edit_adjustments: Iterable[subscription_price_intervals_params.EditAdjustment] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """ This endpoint is used to add and edit subscription - [price intervals](../reference/price-interval). By making modifications to a - subscription’s price intervals, you can - [flexibly and atomically control the billing behavior of a subscription](../guides/product-catalog/modifying-subscriptions). + [price intervals](/api-reference/price-interval/add-or-edit-price-intervals). By + making modifications to a subscription’s price intervals, you can + [flexibly and atomically control the billing behavior of a subscription](/product-catalog/modifying-subscriptions). ## Adding price intervals @@ -2836,6 +3417,21 @@ async def price_intervals( interval. This will only apply to this price interval, not any other price intervals on the subscription. + ## Adjustment intervals + + An adjustment interval represents the time period that a particular adjustment + (a discount, minimum, or maximum) applies to the prices on a subscription. + Adjustment intervals can be added to a subscription by specifying them in the + `add_adjustments` array, or modified via the `edit_adjustments` array. When + creating an adjustment interval, you'll need to provide the definition of the + new adjustment (the type of adjustment, and which prices it applies to), as well + as the start and end dates for the adjustment interval. The start and end dates + of an existing adjustment interval can be edited via the `edit_adjustments` + field (just like price intervals). (To "change" the amount of a discount, + minimum, or maximum, then, you'll need to end the existing interval, and create + a new adjustment interval with the new amount and a start date that matches the + end date of the previous interval.) + ## Editing price intervals Price intervals can be adjusted by specifying edits to make in the `edit` array. @@ -2871,8 +3467,19 @@ async def price_intervals( Args: add: A list of price intervals to add to the subscription. + add_adjustments: A list of adjustments to add to the subscription. + + allow_invoice_credit_or_void: If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + + can_defer_billing: If set, the default value to use for added/edited price intervals with an + end_date set. + edit: A list of price intervals to edit on the subscription. + edit_adjustments: A list of adjustments to edit on the subscription. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -2886,11 +3493,15 @@ async def price_intervals( 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}/price_intervals", + path_template("/subscriptions/{subscription_id}/price_intervals", subscription_id=subscription_id), body=await async_maybe_transform( { "add": add, + "add_adjustments": add_adjustments, + "allow_invoice_credit_or_void": allow_invoice_credit_or_void, + "can_defer_billing": can_defer_billing, "edit": edit, + "edit_adjustments": edit_adjustments, }, subscription_price_intervals_params.SubscriptionPriceIntervalsParams, ), @@ -2901,7 +3512,73 @@ async def price_intervals( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, + ) + + async def redeem_coupon( + self, + subscription_id: str, + *, + change_option: Literal["requested_date", "end_of_subscription_term", "immediate"], + allow_invoice_credit_or_void: Optional[bool] | Omit = omit, + change_date: Union[str, datetime, None] | Omit = omit, + coupon_id: Optional[str] | Omit = omit, + coupon_redemption_code: Optional[str] | Omit = omit, + # 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, + ) -> MutatedSubscription: + """ + Redeem a coupon effective at a given time. + + Args: + allow_invoice_credit_or_void: If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + + change_date: The date that the coupon discount should take effect. This parameter can only be + passed if the `change_option` is `requested_date`. + + coupon_id: Coupon ID to be redeemed for this subscription. + + coupon_redemption_code: Redemption code of the coupon to be redeemed for this subscription. + + 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( + path_template("/subscriptions/{subscription_id}/redeem_coupon", subscription_id=subscription_id), + body=await async_maybe_transform( + { + "change_option": change_option, + "allow_invoice_credit_or_void": allow_invoice_credit_or_void, + "change_date": change_date, + "coupon_id": coupon_id, + "coupon_redemption_code": coupon_redemption_code, + }, + subscription_redeem_coupon_params.SubscriptionRedeemCouponParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=MutatedSubscription, ) async def schedule_plan_change( @@ -2909,98 +3586,311 @@ async def schedule_plan_change( subscription_id: str, *, change_option: Literal["requested_date", "end_of_subscription_term", "immediate"], - align_billing_with_plan_change_date: Optional[bool] | NotGiven = NOT_GIVEN, - billing_cycle_alignment: Optional[Literal["unchanged", "plan_change_date", "start_of_month"]] - | NotGiven = NOT_GIVEN, - change_date: Optional[str] | NotGiven = NOT_GIVEN, - coupon_redemption_code: Optional[str] | NotGiven = NOT_GIVEN, - credits_overage_rate: Optional[float] | NotGiven = NOT_GIVEN, - external_plan_id: Optional[str] | NotGiven = NOT_GIVEN, - initial_phase_order: Optional[int] | NotGiven = NOT_GIVEN, - invoicing_threshold: Optional[str] | NotGiven = NOT_GIVEN, - per_credit_overage_amount: Optional[str] | NotGiven = NOT_GIVEN, - plan_id: Optional[str] | NotGiven = NOT_GIVEN, - price_overrides: Optional[Iterable[subscription_schedule_plan_change_params.PriceOverride]] - | NotGiven = NOT_GIVEN, + add_adjustments: Optional[Iterable[subscription_schedule_plan_change_params.AddAdjustment]] | Omit = omit, + add_prices: Optional[Iterable[subscription_schedule_plan_change_params.AddPrice]] | Omit = omit, + align_billing_with_plan_change_date: Optional[bool] | Omit = omit, + auto_collection: Optional[bool] | Omit = omit, + auto_issuance: Optional[bool] | Omit = omit, + billing_cycle_alignment: Optional[Literal["unchanged", "plan_change_date", "start_of_month"]] | Omit = omit, + billing_cycle_anchor_configuration: Optional[BillingCycleAnchorConfiguration] | Omit = omit, + change_date: Union[str, datetime, None] | Omit = omit, + coupon_redemption_code: Optional[str] | Omit = omit, + credits_overage_rate: Optional[float] | Omit = omit, + default_invoice_memo: Optional[str] | Omit = omit, + external_plan_id: Optional[str] | Omit = omit, + filter: Optional[str] | Omit = omit, + initial_phase_order: Optional[int] | Omit = omit, + invoicing_threshold: Optional[str] | Omit = omit, + net_terms: Optional[int] | Omit = omit, + per_credit_overage_amount: Optional[float] | Omit = omit, + plan_id: Optional[str] | Omit = omit, + plan_version_number: Optional[int] | Omit = omit, + price_overrides: Optional[Iterable[object]] | Omit = omit, + remove_adjustments: Optional[Iterable[subscription_schedule_plan_change_params.RemoveAdjustment]] | Omit = omit, + remove_prices: Optional[Iterable[subscription_schedule_plan_change_params.RemovePrice]] | Omit = omit, + replace_adjustments: Optional[Iterable[subscription_schedule_plan_change_params.ReplaceAdjustment]] + | Omit = omit, + replace_prices: Optional[Iterable[subscription_schedule_plan_change_params.ReplacePrice]] | Omit = omit, + trial_duration_days: Optional[int] | Omit = omit, + usage_customer_ids: Optional[SequenceNotStr[str]] | Omit = omit, # 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, + 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. + ) -> MutatedSubscription: + """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 occurs. 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. + + + 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](/api-reference/price/create-price). See the + [Price resource](/product-catalog/price-configuration) 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`. If `start_date` is unspecified, the start of the phase / plan change + time will be used. If `end_date` is unspecified, it will finish at the end of + the phase / have no end time. + + 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](/api-reference/price/create-price). See the + [Price resource](/product-catalog/price-configuration) 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](/api-reference/subscription/update-price-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](/api-reference/price-interval/add-or-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 `start_date` is unspecified, the start of the phase / plan change + time will be used. If `end_date` is unspecified, it will finish at the end of + the phase / have no end time. + + ### 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](/api-reference/price-interval/add-or-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) + + + Price overrides are being phased out in favor adding/removing/replacing prices. (See + [Customize your customer's subscriptions](/api-reference/subscription/schedule-plan-change)) + + + 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](/product-catalog/price-configuration) 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 + + When scheduling multiple plan changes with the same date, the latest plan change + on that day takes effect. ## Prorations for in-advance fees By default, Orb calculates the prorated difference in any fixed fees when making a plan change, adjusting the customer balance as needed. For details on this behavior, see - [Modifying subscriptions](../guides/product-catalog/modifying-subscriptions.md#prorations-for-in-advance-fees). + [Modifying subscriptions](/product-catalog/modifying-subscriptions#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. + aligned with the plan change's effective date. - billing_cycle_alignment: Reset billing periods to be aligned with the plan change’s effective date or + 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. + + auto_issuance: Used to determine if invoices for this subscription will be automatically + issued. If true, invoices will be automatically issued. If false, invoices will + require manual approval. If `null` is specified, this defaults to the behavior + configured for this customer. + + billing_cycle_alignment: Reset billing periods to be aligned with the plan change's effective date or start of the month. Defaults to `unchanged` which keeps subscription's existing billing cycle alignment. change_date: The date that the plan change should take effect. This parameter can only be - passed if the `change_option` is `requested_date`. + passed if the `change_option` is `requested_date`. If a date with no time is + passed, the plan change will happen at midnight in the customer's timezone. coupon_redemption_code: Redemption code to be used for this subscription. If the coupon cannot be found by its redemption code, or cannot be redeemed, an error response will be - returned and the plan change will not be scheduled. + returned and the subscription creation or plan change will not be scheduled. + + default_invoice_memo: Determines the default memo on this subscription's invoices. Note that if this + is not provided, it is determined by the plan configuration. 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](/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 be issued for the subscription. If not specified, invoices will only be issued at the end of the billing period. + net_terms: The net terms determines the difference between the invoice date and the issue + date for the invoice. If you intend the invoice to be due on issue, set this + to 0. If not provided, this defaults to the value specified in the plan. + 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. + + usage_customer_ids: A list of customer IDs whose usage events will be aggregated and billed under + this subscription. By default, a subscription only considers usage events + associated with its attached customer's customer_id. When usage_customer_ids is + provided, the subscription includes usage events from the specified customers + only. Provided usage_customer_ids must be either the customer for this + subscription itself, or any of that customer's children. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -3014,21 +3904,36 @@ async def schedule_plan_change( 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}/schedule_plan_change", + path_template("/subscriptions/{subscription_id}/schedule_plan_change", subscription_id=subscription_id), 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, + "auto_issuance": auto_issuance, "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, + "usage_customer_ids": usage_customer_ids, }, subscription_schedule_plan_change_params.SubscriptionSchedulePlanChangeParams, ), @@ -3039,27 +3944,32 @@ async def schedule_plan_change( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, ) async def trigger_phase( self, subscription_id: str, *, - effective_date: Union[str, date, None] | NotGiven = NOT_GIVEN, + allow_invoice_credit_or_void: Optional[bool] | Omit = omit, + effective_date: Union[str, date, None] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """ Manually trigger a phase, effective the given date (or the current time, if not specified). Args: + allow_invoice_credit_or_void: If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + effective_date: The date on which the phase change should take effect. If not provided, defaults to today in the customer's timezone. @@ -3076,9 +3986,13 @@ async def trigger_phase( 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}/trigger_phase", + path_template("/subscriptions/{subscription_id}/trigger_phase", subscription_id=subscription_id), body=await async_maybe_transform( - {"effective_date": effective_date}, subscription_trigger_phase_params.SubscriptionTriggerPhaseParams + { + "allow_invoice_credit_or_void": allow_invoice_credit_or_void, + "effective_date": effective_date, + }, + subscription_trigger_phase_params.SubscriptionTriggerPhaseParams, ), options=make_request_options( extra_headers=extra_headers, @@ -3087,7 +4001,7 @@ async def trigger_phase( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, ) async def unschedule_cancellation( @@ -3099,9 +4013,9 @@ async def unschedule_cancellation( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """ This endpoint can be used to unschedule any pending cancellations for a subscription. @@ -3110,6 +4024,12 @@ async def unschedule_cancellation( cancellation. This operation will turn on auto-renew, ensuring that the subscription does not end at the currently scheduled cancellation time. + Note: uncancellation is a lossy operation. Price intervals that were cut short + by the cancellation are extended to infinity (original end dates are lost), and + future intervals or phases scheduled after the cancellation time are permanently + deleted. For complex subscriptions with phases or scheduled plan changes, + consider creating a new plan change instead of uncancelling. + Args: extra_headers: Send extra headers @@ -3124,7 +4044,7 @@ async def unschedule_cancellation( 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}/unschedule_cancellation", + path_template("/subscriptions/{subscription_id}/unschedule_cancellation", subscription_id=subscription_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -3132,7 +4052,7 @@ async def unschedule_cancellation( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, ) async def unschedule_fixed_fee_quantity_updates( @@ -3145,14 +4065,15 @@ async def unschedule_fixed_fee_quantity_updates( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """ This endpoint can be used to clear scheduled updates to the quantity for a fixed fee. - If there are no updates scheduled, this endpoint is a no-op. + If there are no updates scheduled, a request validation error will be returned + with a 400 status code. Args: price_id: Price for which the updates should be cleared. Must be a fixed fee. @@ -3170,7 +4091,10 @@ async def unschedule_fixed_fee_quantity_updates( 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}/unschedule_fixed_fee_quantity_updates", + path_template( + "/subscriptions/{subscription_id}/unschedule_fixed_fee_quantity_updates", + subscription_id=subscription_id, + ), body=await async_maybe_transform( {"price_id": price_id}, subscription_unschedule_fixed_fee_quantity_updates_params.SubscriptionUnscheduleFixedFeeQuantityUpdatesParams, @@ -3182,7 +4106,7 @@ async def unschedule_fixed_fee_quantity_updates( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, ) async def unschedule_pending_plan_changes( @@ -3194,12 +4118,12 @@ async def unschedule_pending_plan_changes( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """ This endpoint can be used to unschedule any pending plan changes on an existing - subscription. + subscription. When called, all upcoming plan changes will be unscheduled. Args: extra_headers: Send extra headers @@ -3215,7 +4139,9 @@ async def unschedule_pending_plan_changes( 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}/unschedule_pending_plan_changes", + path_template( + "/subscriptions/{subscription_id}/unschedule_pending_plan_changes", subscription_id=subscription_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -3223,7 +4149,7 @@ async def unschedule_pending_plan_changes( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, ) async def update_fixed_fee_quantity( @@ -3232,16 +4158,17 @@ async def update_fixed_fee_quantity( *, price_id: str, quantity: float, - change_option: Literal["immediate", "upcoming_invoice", "effective_date"] | NotGiven = NOT_GIVEN, - effective_date: Union[str, date, None] | NotGiven = NOT_GIVEN, + allow_invoice_credit_or_void: Optional[bool] | Omit = omit, + change_option: Literal["immediate", "upcoming_invoice", "effective_date"] | Omit = omit, + effective_date: Union[str, date, None] | Omit = omit, # 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, - ) -> Subscription: + ) -> MutatedSubscription: """ This endpoint can be used to update the quantity for a fixed fee. @@ -3261,12 +4188,16 @@ async def update_fixed_fee_quantity( Args: price_id: Price for which the quantity should be updated. Must be a fixed fee. + allow_invoice_credit_or_void: If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + change_option: Determines when the change takes effect. Note that if `effective_date` is specified, this defaults to `effective_date`. Otherwise, this defaults to - `immediate` unless it's explicitly set to `upcoming_invoice. + `immediate` unless it's explicitly set to `upcoming_invoice`. effective_date: The date that the quantity change should take effect, localized to the - customer's timezone. Ifthis parameter is not passed in, the quantity change is + customer's timezone. If this parameter is not passed in, the quantity change is effective according to `change_option`. extra_headers: Send extra headers @@ -3282,11 +4213,14 @@ async def update_fixed_fee_quantity( 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_fixed_fee_quantity", + path_template( + "/subscriptions/{subscription_id}/update_fixed_fee_quantity", subscription_id=subscription_id + ), body=await async_maybe_transform( { "price_id": price_id, "quantity": quantity, + "allow_invoice_credit_or_void": allow_invoice_credit_or_void, "change_option": change_option, "effective_date": effective_date, }, @@ -3299,7 +4233,80 @@ async def update_fixed_fee_quantity( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=MutatedSubscription, + ) + + async def update_trial( + self, + subscription_id: str, + *, + trial_end_date: Union[Union[str, datetime], Literal["immediate"]], + shift: bool | Omit = omit, + # 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, + ) -> MutatedSubscription: + """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( + path_template("/subscriptions/{subscription_id}/update_trial", subscription_id=subscription_id), + 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=MutatedSubscription, ) @@ -3310,6 +4317,9 @@ def __init__(self, subscriptions: Subscriptions) -> None: self.create = _legacy_response.to_raw_response_wrapper( subscriptions.create, ) + self.update = _legacy_response.to_raw_response_wrapper( + subscriptions.update, + ) self.list = _legacy_response.to_raw_response_wrapper( subscriptions.list, ) @@ -3331,6 +4341,9 @@ def __init__(self, subscriptions: Subscriptions) -> None: self.price_intervals = _legacy_response.to_raw_response_wrapper( subscriptions.price_intervals, ) + self.redeem_coupon = _legacy_response.to_raw_response_wrapper( + subscriptions.redeem_coupon, + ) self.schedule_plan_change = _legacy_response.to_raw_response_wrapper( subscriptions.schedule_plan_change, ) @@ -3349,6 +4362,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: @@ -3358,6 +4374,9 @@ def __init__(self, subscriptions: AsyncSubscriptions) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( subscriptions.create, ) + self.update = _legacy_response.async_to_raw_response_wrapper( + subscriptions.update, + ) self.list = _legacy_response.async_to_raw_response_wrapper( subscriptions.list, ) @@ -3379,6 +4398,9 @@ def __init__(self, subscriptions: AsyncSubscriptions) -> None: self.price_intervals = _legacy_response.async_to_raw_response_wrapper( subscriptions.price_intervals, ) + self.redeem_coupon = _legacy_response.async_to_raw_response_wrapper( + subscriptions.redeem_coupon, + ) self.schedule_plan_change = _legacy_response.async_to_raw_response_wrapper( subscriptions.schedule_plan_change, ) @@ -3397,6 +4419,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: @@ -3406,6 +4431,9 @@ def __init__(self, subscriptions: Subscriptions) -> None: self.create = to_streamed_response_wrapper( subscriptions.create, ) + self.update = to_streamed_response_wrapper( + subscriptions.update, + ) self.list = to_streamed_response_wrapper( subscriptions.list, ) @@ -3427,6 +4455,9 @@ def __init__(self, subscriptions: Subscriptions) -> None: self.price_intervals = to_streamed_response_wrapper( subscriptions.price_intervals, ) + self.redeem_coupon = to_streamed_response_wrapper( + subscriptions.redeem_coupon, + ) self.schedule_plan_change = to_streamed_response_wrapper( subscriptions.schedule_plan_change, ) @@ -3445,6 +4476,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: @@ -3454,6 +4488,9 @@ def __init__(self, subscriptions: AsyncSubscriptions) -> None: self.create = async_to_streamed_response_wrapper( subscriptions.create, ) + self.update = async_to_streamed_response_wrapper( + subscriptions.update, + ) self.list = async_to_streamed_response_wrapper( subscriptions.list, ) @@ -3475,6 +4512,9 @@ def __init__(self, subscriptions: AsyncSubscriptions) -> None: self.price_intervals = async_to_streamed_response_wrapper( subscriptions.price_intervals, ) + self.redeem_coupon = async_to_streamed_response_wrapper( + subscriptions.redeem_coupon, + ) self.schedule_plan_change = async_to_streamed_response_wrapper( subscriptions.schedule_plan_change, ) @@ -3493,3 +4533,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 9b1d3baa..e1330fdd 100644 --- a/src/orb/resources/top_level.py +++ b/src/orb/resources/top_level.py @@ -5,14 +5,12 @@ import httpx from .. import _legacy_response -from ..types import TopLevelPingResponse -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Query, Headers, NotGiven, not_given 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 .._base_client import make_request_options +from ..types.top_level_ping_response import TopLevelPingResponse __all__ = ["TopLevel", "AsyncTopLevel"] @@ -20,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 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( @@ -34,7 +43,7 @@ def ping( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TopLevelPingResponse: """ This endpoint allows you to test your connection to the Orb API and check the @@ -56,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 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( @@ -70,7 +90,7 @@ async def ping( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TopLevelPingResponse: """ This endpoint allows you to test your connection to the Orb API and check the diff --git a/src/orb/types/__init__.py b/src/orb/types/__init__.py index 7f77612c..888766fa 100644 --- a/src/orb/types/__init__.py +++ b/src/orb/types/__init__.py @@ -4,65 +4,344 @@ from .item import Item as Item from .plan import Plan as Plan -from .price import Price as Price +from .alert import Alert as Alert from .coupon import Coupon as Coupon -from .shared import Discount as Discount -from .invoice import Invoice as Invoice +from .shared import ( + Tier as Tier, + Price as Price, + Address as Address, + Invoice as Invoice, + Maximum as Maximum, + Minimum as Minimum, + BulkTier as BulkTier, + Discount as Discount, + ItemSlim as ItemSlim, + TaxAmount as TaxAmount, + Allocation as Allocation, + BulkConfig as BulkConfig, + CreditNote as CreditNote, + NewMaximum as NewMaximum, + NewMinimum as NewMinimum, + UnitConfig as UnitConfig, + InvoiceTiny as InvoiceTiny, + MatrixValue as MatrixValue, + MatrixConfig as MatrixConfig, + PerPriceCost as PerPriceCost, + TieredConfig as TieredConfig, + CustomerTaxID as CustomerTaxID, + PackageConfig as PackageConfig, + PriceInterval as PriceInterval, + TrialDiscount as TrialDiscount, + UsageDiscount as UsageDiscount, + AggregatedCost as AggregatedCost, + AmountDiscount as AmountDiscount, + CreditNoteTiny as CreditNoteTiny, + MaximumInterval as MaximumInterval, + MinimumInterval as MinimumInterval, + TierSubLineItem as TierSubLineItem, + CouponRedemption as CouponRedemption, + CustomerMinified as CustomerMinified, + CustomExpiration as CustomExpiration, + NewPlanBulkPrice as NewPlanBulkPrice, + NewPlanUnitPrice as NewPlanUnitPrice, + NewUsageDiscount as NewUsageDiscount, + OtherSubLineItem as OtherSubLineItem, + MatrixSubLineItem as MatrixSubLineItem, + NewAmountDiscount as NewAmountDiscount, + AdjustmentInterval as AdjustmentInterval, + BillableMetricTiny as BillableMetricTiny, + ConversionRateTier as ConversionRateTier, + NewAllocationPrice as NewAllocationPrice, + NewPlanMatrixPrice as NewPlanMatrixPrice, + NewPlanTieredPrice as NewPlanTieredPrice, + PaginationMetadata as PaginationMetadata, + PercentageDiscount as PercentageDiscount, + NewPlanPackagePrice as NewPlanPackagePrice, + SubLineItemGrouping as SubLineItemGrouping, + InvoiceLevelDiscount as InvoiceLevelDiscount, + NewFloatingBulkPrice as NewFloatingBulkPrice, + NewFloatingUnitPrice as NewFloatingUnitPrice, + SubscriptionMinified as SubscriptionMinified, + NewPercentageDiscount as NewPercentageDiscount, + SubscriptionTrialInfo as SubscriptionTrialInfo, + UsageDiscountInterval as UsageDiscountInterval, + AmountDiscountInterval as AmountDiscountInterval, + NewFloatingMatrixPrice as NewFloatingMatrixPrice, + NewFloatingTieredPrice as NewFloatingTieredPrice, + NewFloatingPackagePrice as NewFloatingPackagePrice, + SubLineItemMatrixConfig as SubLineItemMatrixConfig, + BillingCycleRelativeDate as BillingCycleRelativeDate, + ConversionRateUnitConfig as ConversionRateUnitConfig, + UnitConversionRateConfig as UnitConversionRateConfig, + BillingCycleConfiguration as BillingCycleConfiguration, + MonetaryMaximumAdjustment as MonetaryMaximumAdjustment, + MonetaryMinimumAdjustment as MonetaryMinimumAdjustment, + NewPlanGroupedTieredPrice as NewPlanGroupedTieredPrice, + NewPlanTieredPackagePrice as NewPlanTieredPackagePrice, + ConversionRateTieredConfig as ConversionRateTieredConfig, + FixedFeeQuantityTransition as FixedFeeQuantityTransition, + MatrixWithAllocationConfig as MatrixWithAllocationConfig, + PercentageDiscountInterval as PercentageDiscountInterval, + PlanPhaseMaximumAdjustment as PlanPhaseMaximumAdjustment, + PlanPhaseMinimumAdjustment as PlanPhaseMinimumAdjustment, + SubscriptionChangeMinified as SubscriptionChangeMinified, + TieredConversionRateConfig as TieredConversionRateConfig, + NewPlanUnitWithPercentPrice as NewPlanUnitWithPercentPrice, + ChangedSubscriptionResources as ChangedSubscriptionResources, + NewBillingCycleConfiguration as NewBillingCycleConfiguration, + NewPlanMinimumCompositePrice as NewPlanMinimumCompositePrice, + DimensionalPriceConfiguration as DimensionalPriceConfiguration, + FixedFeeQuantityScheduleEntry as FixedFeeQuantityScheduleEntry, + NewFloatingGroupedTieredPrice as NewFloatingGroupedTieredPrice, + NewFloatingTieredPackagePrice as NewFloatingTieredPackagePrice, + NewPlanBulkWithProrationPrice as NewPlanBulkWithProrationPrice, + NewPlanGroupedAllocationPrice as NewPlanGroupedAllocationPrice, + NewPlanTieredWithMinimumPrice as NewPlanTieredWithMinimumPrice, + NewPlanUnitWithProrationPrice as NewPlanUnitWithProrationPrice, + BillingCycleAnchorConfiguration as BillingCycleAnchorConfiguration, + MonetaryUsageDiscountAdjustment as MonetaryUsageDiscountAdjustment, + NewFloatingUnitWithPercentPrice as NewFloatingUnitWithPercentPrice, + MonetaryAmountDiscountAdjustment as MonetaryAmountDiscountAdjustment, + NewDimensionalPriceConfiguration as NewDimensionalPriceConfiguration, + NewFloatingMinimumCompositePrice as NewFloatingMinimumCompositePrice, + NewPlanGroupedTieredPackagePrice as NewPlanGroupedTieredPackagePrice, + NewPlanMatrixWithAllocationPrice as NewPlanMatrixWithAllocationPrice, + NewPlanThresholdTotalAmountPrice as NewPlanThresholdTotalAmountPrice, + PlanPhaseUsageDiscountAdjustment as PlanPhaseUsageDiscountAdjustment, + NewFloatingBulkWithProrationPrice as NewFloatingBulkWithProrationPrice, + NewFloatingGroupedAllocationPrice as NewFloatingGroupedAllocationPrice, + NewFloatingTieredWithMinimumPrice as NewFloatingTieredWithMinimumPrice, + NewFloatingUnitWithProrationPrice as NewFloatingUnitWithProrationPrice, + NewPlanCumulativeGroupedBulkPrice as NewPlanCumulativeGroupedBulkPrice, + NewPlanMatrixWithDisplayNamePrice as NewPlanMatrixWithDisplayNamePrice, + NewPlanMaxGroupTieredPackagePrice as NewPlanMaxGroupTieredPackagePrice, + NewPlanPackageWithAllocationPrice as NewPlanPackageWithAllocationPrice, + PlanPhaseAmountDiscountAdjustment as PlanPhaseAmountDiscountAdjustment, + NewFloatingTieredWithProrationPrice as NewFloatingTieredWithProrationPrice, + MonetaryPercentageDiscountAdjustment as MonetaryPercentageDiscountAdjustment, + NewFloatingGroupedTieredPackagePrice as NewFloatingGroupedTieredPackagePrice, + NewFloatingMatrixWithAllocationPrice as NewFloatingMatrixWithAllocationPrice, + NewFloatingThresholdTotalAmountPrice as NewFloatingThresholdTotalAmountPrice, + NewPlanTieredPackageWithMinimumPrice as NewPlanTieredPackageWithMinimumPrice, + NewFloatingCumulativeGroupedBulkPrice as NewFloatingCumulativeGroupedBulkPrice, + NewFloatingMatrixWithDisplayNamePrice as NewFloatingMatrixWithDisplayNamePrice, + NewFloatingMaxGroupTieredPackagePrice as NewFloatingMaxGroupTieredPackagePrice, + NewFloatingPackageWithAllocationPrice as NewFloatingPackageWithAllocationPrice, + NewPlanGroupedWithMeteredMinimumPrice as NewPlanGroupedWithMeteredMinimumPrice, + PlanPhasePercentageDiscountAdjustment as PlanPhasePercentageDiscountAdjustment, + NewPlanGroupedWithProratedMinimumPrice as NewPlanGroupedWithProratedMinimumPrice, + NewFloatingTieredPackageWithMinimumPrice as NewFloatingTieredPackageWithMinimumPrice, + NewFloatingGroupedWithMeteredMinimumPrice as NewFloatingGroupedWithMeteredMinimumPrice, + NewPlanScalableMatrixWithUnitPricingPrice as NewPlanScalableMatrixWithUnitPricingPrice, + NewFloatingGroupedWithProratedMinimumPrice as NewFloatingGroupedWithProratedMinimumPrice, + NewPlanScalableMatrixWithTieredPricingPrice as NewPlanScalableMatrixWithTieredPricingPrice, + NewFloatingScalableMatrixWithUnitPricingPrice as NewFloatingScalableMatrixWithUnitPricingPrice, + NewFloatingScalableMatrixWithTieredPricingPrice as NewFloatingScalableMatrixWithTieredPricingPrice, +) from .customer import Customer as Customer -from .credit_note import CreditNote as CreditNote +from .threshold import Threshold as Threshold +from .plan_version import PlanVersion as PlanVersion from .subscription import Subscription as Subscription from .subscriptions import Subscriptions as Subscriptions +from .billable_metric import BillableMetric as BillableMetric +from .threshold_param import ThresholdParam as ThresholdParam from .item_list_params import ItemListParams as ItemListParams from .plan_list_params import PlanListParams as PlanListParams +from .alert_list_params import AlertListParams as AlertListParams from .price_list_params import PriceListParams as PriceListParams from .coupon_list_params import CouponListParams as CouponListParams +from .invoice_pay_params import InvoicePayParams as InvoicePayParams from .item_create_params import ItemCreateParams as ItemCreateParams +from .item_update_params import ItemUpdateParams as ItemUpdateParams from .metric_list_params import MetricListParams as MetricListParams from .plan_create_params import PlanCreateParams as PlanCreateParams from .plan_update_params import PlanUpdateParams as PlanUpdateParams +from .plan_version_phase import PlanVersionPhase as PlanVersionPhase from .subscription_usage import SubscriptionUsage as SubscriptionUsage +from .address_input_param import AddressInputParam as AddressInputParam +from .alert_enable_params import AlertEnableParams as AlertEnableParams +from .alert_update_params import AlertUpdateParams as AlertUpdateParams from .event_ingest_params import EventIngestParams as EventIngestParams from .event_search_params import EventSearchParams as EventSearchParams from .event_update_params import EventUpdateParams as EventUpdateParams from .invoice_list_params import InvoiceListParams as InvoiceListParams +from .license_list_params import LicenseListParams as LicenseListParams from .price_create_params import PriceCreateParams as PriceCreateParams +from .price_update_params import PriceUpdateParams as PriceUpdateParams +from .alert_disable_params import AlertDisableParams as AlertDisableParams 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_list_response import MetricListResponse as MetricListResponse +from .metric_update_params import MetricUpdateParams as MetricUpdateParams +from .mutated_subscription import MutatedSubscription as MutatedSubscription from .event_ingest_response import EventIngestResponse as EventIngestResponse from .event_search_response import EventSearchResponse as EventSearchResponse from .event_update_response import EventUpdateResponse as EventUpdateResponse from .invoice_create_params import InvoiceCreateParams as InvoiceCreateParams -from .metric_fetch_response import MetricFetchResponse as MetricFetchResponse +from .invoice_update_params import InvoiceUpdateParams as InvoiceUpdateParams +from .license_create_params import LicenseCreateParams as LicenseCreateParams +from .license_list_response import LicenseListResponse as LicenseListResponse +from .price_evaluate_params import PriceEvaluateParams as PriceEvaluateParams from .customer_create_params import CustomerCreateParams as CustomerCreateParams from .customer_update_params import CustomerUpdateParams as CustomerUpdateParams -from .metric_create_response import MetricCreateResponse as MetricCreateResponse from .credit_note_list_params import CreditNoteListParams as CreditNoteListParams +from .dimensional_price_group import DimensionalPriceGroup as DimensionalPriceGroup +from .discount_override_param import DiscountOverrideParam as DiscountOverrideParam +from .license_create_response import LicenseCreateResponse as LicenseCreateResponse +from .price_evaluate_response import PriceEvaluateResponse as PriceEvaluateResponse from .top_level_ping_response import TopLevelPingResponse as TopLevelPingResponse +from .dimensional_price_groups import DimensionalPriceGroups as DimensionalPriceGroups from .event_deprecate_response import EventDeprecateResponse as EventDeprecateResponse from .invoice_mark_paid_params import InvoiceMarkPaidParams as InvoiceMarkPaidParams +from .license_type_list_params import LicenseTypeListParams as LicenseTypeListParams from .subscription_list_params import SubscriptionListParams as SubscriptionListParams +from .credit_note_create_params import CreditNoteCreateParams as CreditNoteCreateParams +from .license_deactivate_params import LicenseDeactivateParams as LicenseDeactivateParams +from .license_retrieve_response import LicenseRetrieveResponse as LicenseRetrieveResponse +from .license_type_create_params import LicenseTypeCreateParams as LicenseTypeCreateParams +from .license_type_list_response import LicenseTypeListResponse as LicenseTypeListResponse 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 .invoice_list_summary_params import InvoiceListSummaryParams as InvoiceListSummaryParams +from .license_deactivate_response import LicenseDeactivateResponse as LicenseDeactivateResponse +from .invoice_issue_summary_params import InvoiceIssueSummaryParams as InvoiceIssueSummaryParams +from .license_type_create_response import LicenseTypeCreateResponse as LicenseTypeCreateResponse from .invoice_fetch_upcoming_params import InvoiceFetchUpcomingParams as InvoiceFetchUpcomingParams +from .invoice_list_summary_response import InvoiceListSummaryResponse as InvoiceListSummaryResponse +from .credit_block_retrieve_response import CreditBlockRetrieveResponse as CreditBlockRetrieveResponse +from .invoice_issue_summary_response import InvoiceIssueSummaryResponse as InvoiceIssueSummaryResponse +from .license_type_retrieve_response import LicenseTypeRetrieveResponse as LicenseTypeRetrieveResponse +from .new_sphere_configuration_param import NewSphereConfigurationParam as NewSphereConfigurationParam +from .price_evaluate_multiple_params import PriceEvaluateMultipleParams as PriceEvaluateMultipleParams +from .beta_create_plan_version_params import BetaCreatePlanVersionParams as BetaCreatePlanVersionParams +from .customer_hierarchy_config_param import CustomerHierarchyConfigParam as CustomerHierarchyConfigParam from .invoice_fetch_upcoming_response import InvoiceFetchUpcomingResponse as InvoiceFetchUpcomingResponse from .invoice_line_item_create_params import InvoiceLineItemCreateParams as InvoiceLineItemCreateParams +from .new_tax_jar_configuration_param import NewTaxJarConfigurationParam as NewTaxJarConfigurationParam +from .subscription_change_list_params import SubscriptionChangeListParams as SubscriptionChangeListParams from .subscription_fetch_costs_params import SubscriptionFetchCostsParams as SubscriptionFetchCostsParams from .subscription_fetch_usage_params import SubscriptionFetchUsageParams as SubscriptionFetchUsageParams +from .accounting_provider_config_param import AccountingProviderConfigParam as AccountingProviderConfigParam +from .alert_create_for_customer_params import AlertCreateForCustomerParams as AlertCreateForCustomerParams +from .price_evaluate_multiple_response import PriceEvaluateMultipleResponse as PriceEvaluateMultipleResponse +from .subscription_change_apply_params import SubscriptionChangeApplyParams as SubscriptionChangeApplyParams +from .subscription_update_trial_params import SubscriptionUpdateTrialParams as SubscriptionUpdateTrialParams from .invoice_line_item_create_response import InvoiceLineItemCreateResponse as InvoiceLineItemCreateResponse +from .new_reporting_configuration_param import NewReportingConfigurationParam as NewReportingConfigurationParam +from .new_subscription_bulk_price_param import NewSubscriptionBulkPriceParam as NewSubscriptionBulkPriceParam +from .new_subscription_unit_price_param import NewSubscriptionUnitPriceParam as NewSubscriptionUnitPriceParam +from .subscription_change_list_response import SubscriptionChangeListResponse as SubscriptionChangeListResponse from .subscription_fetch_costs_response import SubscriptionFetchCostsResponse as SubscriptionFetchCostsResponse +from .subscription_redeem_coupon_params import SubscriptionRedeemCouponParams as SubscriptionRedeemCouponParams from .subscription_trigger_phase_params import SubscriptionTriggerPhaseParams as SubscriptionTriggerPhaseParams +from .subscription_change_apply_response import SubscriptionChangeApplyResponse as SubscriptionChangeApplyResponse from .subscription_fetch_schedule_params import SubscriptionFetchScheduleParams as SubscriptionFetchScheduleParams +from .credit_block_list_invoices_response import CreditBlockListInvoicesResponse as CreditBlockListInvoicesResponse +from .dimensional_price_group_list_params import DimensionalPriceGroupListParams as DimensionalPriceGroupListParams +from .new_avalara_tax_configuration_param import NewAvalaraTaxConfigurationParam as NewAvalaraTaxConfigurationParam +from .new_subscription_matrix_price_param import NewSubscriptionMatrixPriceParam as NewSubscriptionMatrixPriceParam +from .new_subscription_tiered_price_param import NewSubscriptionTieredPriceParam as NewSubscriptionTieredPriceParam +from .subscription_change_cancel_response import SubscriptionChangeCancelResponse as SubscriptionChangeCancelResponse from .subscription_price_intervals_params import SubscriptionPriceIntervalsParams as SubscriptionPriceIntervalsParams +from .alert_create_for_subscription_params import AlertCreateForSubscriptionParams as AlertCreateForSubscriptionParams +from .beta_set_default_plan_version_params import BetaSetDefaultPlanVersionParams as BetaSetDefaultPlanVersionParams +from .new_subscription_package_price_param import NewSubscriptionPackagePriceParam as NewSubscriptionPackagePriceParam +from .price_evaluate_preview_events_params import PriceEvaluatePreviewEventsParams as PriceEvaluatePreviewEventsParams from .subscription_fetch_schedule_response import SubscriptionFetchScheduleResponse as SubscriptionFetchScheduleResponse from .customer_update_by_external_id_params import CustomerUpdateByExternalIDParams as CustomerUpdateByExternalIDParams +from .dimensional_price_group_create_params import ( + DimensionalPriceGroupCreateParams as DimensionalPriceGroupCreateParams, +) +from .dimensional_price_group_update_params import ( + DimensionalPriceGroupUpdateParams as DimensionalPriceGroupUpdateParams, +) +from .subscription_change_retrieve_response import ( + SubscriptionChangeRetrieveResponse as SubscriptionChangeRetrieveResponse, +) +from .license_retrieve_by_external_id_params import ( + LicenseRetrieveByExternalIDParams as LicenseRetrieveByExternalIDParams, +) +from .price_evaluate_preview_events_response import ( + PriceEvaluatePreviewEventsResponse as PriceEvaluatePreviewEventsResponse, +) +from .new_accounting_sync_configuration_param import ( + NewAccountingSyncConfigurationParam as NewAccountingSyncConfigurationParam, +) +from .license_retrieve_by_external_id_response import ( + LicenseRetrieveByExternalIDResponse as LicenseRetrieveByExternalIDResponse, +) from .subscription_schedule_plan_change_params import ( SubscriptionSchedulePlanChangeParams as SubscriptionSchedulePlanChangeParams, ) +from .alert_create_for_external_customer_params import ( + AlertCreateForExternalCustomerParams as AlertCreateForExternalCustomerParams, +) +from .new_subscription_grouped_tiered_price_param import ( + NewSubscriptionGroupedTieredPriceParam as NewSubscriptionGroupedTieredPriceParam, +) +from .new_subscription_tiered_package_price_param import ( + NewSubscriptionTieredPackagePriceParam as NewSubscriptionTieredPackagePriceParam, +) from .subscription_update_fixed_fee_quantity_params import ( SubscriptionUpdateFixedFeeQuantityParams as SubscriptionUpdateFixedFeeQuantityParams, ) +from .new_subscription_minimum_composite_price_param import ( + NewSubscriptionMinimumCompositePriceParam as NewSubscriptionMinimumCompositePriceParam, +) +from .new_subscription_unit_with_percent_price_param import ( + NewSubscriptionUnitWithPercentPriceParam as NewSubscriptionUnitWithPercentPriceParam, +) +from .new_subscription_grouped_allocation_price_param import ( + NewSubscriptionGroupedAllocationPriceParam as NewSubscriptionGroupedAllocationPriceParam, +) +from .new_subscription_bulk_with_proration_price_param import ( + NewSubscriptionBulkWithProrationPriceParam as NewSubscriptionBulkWithProrationPriceParam, +) +from .new_subscription_tiered_with_minimum_price_param import ( + NewSubscriptionTieredWithMinimumPriceParam as NewSubscriptionTieredWithMinimumPriceParam, +) +from .new_subscription_unit_with_proration_price_param import ( + NewSubscriptionUnitWithProrationPriceParam as NewSubscriptionUnitWithProrationPriceParam, +) +from .new_subscription_grouped_tiered_package_price_param import ( + NewSubscriptionGroupedTieredPackagePriceParam as NewSubscriptionGroupedTieredPackagePriceParam, +) +from .new_subscription_matrix_with_allocation_price_param import ( + NewSubscriptionMatrixWithAllocationPriceParam as NewSubscriptionMatrixWithAllocationPriceParam, +) +from .new_subscription_threshold_total_amount_price_param import ( + NewSubscriptionThresholdTotalAmountPriceParam as NewSubscriptionThresholdTotalAmountPriceParam, +) +from .new_subscription_cumulative_grouped_bulk_price_param import ( + NewSubscriptionCumulativeGroupedBulkPriceParam as NewSubscriptionCumulativeGroupedBulkPriceParam, +) +from .new_subscription_package_with_allocation_price_param import ( + NewSubscriptionPackageWithAllocationPriceParam as NewSubscriptionPackageWithAllocationPriceParam, +) +from .new_subscription_matrix_with_display_name_price_param import ( + NewSubscriptionMatrixWithDisplayNamePriceParam as NewSubscriptionMatrixWithDisplayNamePriceParam, +) +from .new_subscription_max_group_tiered_package_price_param import ( + NewSubscriptionMaxGroupTieredPackagePriceParam as NewSubscriptionMaxGroupTieredPackagePriceParam, +) +from .new_subscription_tiered_package_with_minimum_price_param import ( + NewSubscriptionTieredPackageWithMinimumPriceParam as NewSubscriptionTieredPackageWithMinimumPriceParam, +) +from .new_subscription_grouped_with_metered_minimum_price_param import ( + NewSubscriptionGroupedWithMeteredMinimumPriceParam as NewSubscriptionGroupedWithMeteredMinimumPriceParam, +) from .subscription_unschedule_fixed_fee_quantity_updates_params import ( SubscriptionUnscheduleFixedFeeQuantityUpdatesParams as SubscriptionUnscheduleFixedFeeQuantityUpdatesParams, ) +from .new_subscription_grouped_with_prorated_minimum_price_param import ( + NewSubscriptionGroupedWithProratedMinimumPriceParam as NewSubscriptionGroupedWithProratedMinimumPriceParam, +) +from .new_subscription_scalable_matrix_with_unit_pricing_price_param import ( + NewSubscriptionScalableMatrixWithUnitPricingPriceParam as NewSubscriptionScalableMatrixWithUnitPricingPriceParam, +) +from .new_subscription_scalable_matrix_with_tiered_pricing_price_param import ( + NewSubscriptionScalableMatrixWithTieredPricingPriceParam as NewSubscriptionScalableMatrixWithTieredPricingPriceParam, +) diff --git a/src/orb/types/accounting_provider_config_param.py b/src/orb/types/accounting_provider_config_param.py new file mode 100644 index 00000000..9d98e49d --- /dev/null +++ b/src/orb/types/accounting_provider_config_param.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["AccountingProviderConfigParam"] + + +class AccountingProviderConfigParam(TypedDict, total=False): + external_provider_id: Required[str] + + provider_type: Required[Literal["quickbooks", "netsuite"]] diff --git a/src/orb/types/address_input_param.py b/src/orb/types/address_input_param.py new file mode 100644 index 00000000..c1666475 --- /dev/null +++ b/src/orb/types/address_input_param.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +__all__ = ["AddressInputParam"] + + +class AddressInputParam(TypedDict, total=False): + city: Optional[str] + + country: Optional[str] + + line1: Optional[str] + + line2: Optional[str] + + postal_code: Optional[str] + + state: Optional[str] diff --git a/src/orb/types/alert.py b/src/orb/types/alert.py new file mode 100644 index 00000000..9381a4a3 --- /dev/null +++ b/src/orb/types/alert.py @@ -0,0 +1,157 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel +from .threshold import Threshold +from .shared.customer_minified import CustomerMinified +from .shared.subscription_minified import SubscriptionMinified + +__all__ = ["Alert", "Metric", "Plan", "BalanceAlertStatus", "LicenseType", "PriceFilter", "ThresholdOverride"] + + +class Metric(BaseModel): + """The metric the alert applies to.""" + + id: str + + +class Plan(BaseModel): + """The plan the alert applies to.""" + + id: Optional[str] = None + + external_plan_id: Optional[str] = None + """ + An optional user-defined ID for this plan resource, used throughout the system + as an alias for this Plan. Use this field to identify a plan by an existing + identifier in your system. + """ + + name: Optional[str] = None + + plan_version: str + + +class BalanceAlertStatus(BaseModel): + """Alert status is used to determine if an alert is currently in-alert or not.""" + + in_alert: bool + """Whether the alert is currently in-alert or not.""" + + threshold_value: float + """The value of the threshold that defines the alert status.""" + + +class LicenseType(BaseModel): + """Minified license type for alert serialization.""" + + id: str + + +class PriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class ThresholdOverride(BaseModel): + """A per-group threshold override on a grouped cost alert. + + An empty `thresholds` list means the group is silenced (never fires). + A non-empty list fully replaces the default thresholds for that group. + """ + + group_values: List[str] + """The values of the grouping keys that identify this group. + + The list length matches the alert's grouping_keys. + """ + + thresholds: List[Threshold] + """The thresholds applied to this group. + + An empty list means the group is silenced. + """ + + +class Alert(BaseModel): + """ + [Alerts within Orb](/product-catalog/configuring-alerts) monitor spending, + usage, or credit balance and trigger webhooks when a threshold is exceeded. + + Alerts created through the API can be scoped to either customers or subscriptions. + """ + + id: str + """Also referred to as alert_id in this documentation.""" + + created_at: datetime + """The creation time of the resource in Orb.""" + + currency: Optional[str] = None + """The name of the currency the credit balance or invoice cost is denominated in.""" + + customer: Optional[CustomerMinified] = None + """The customer the alert applies to.""" + + enabled: bool + """Whether the alert is enabled or disabled.""" + + metric: Optional[Metric] = None + """The metric the alert applies to.""" + + plan: Optional[Plan] = None + """The plan the alert applies to.""" + + subscription: Optional[SubscriptionMinified] = None + """The subscription the alert applies to.""" + + thresholds: Optional[List[Threshold]] = None + """ + The thresholds that define the conditions under which the alert will be + triggered. + """ + + type: Literal[ + "credit_balance_depleted", + "credit_balance_dropped", + "credit_balance_recovered", + "usage_exceeded", + "cost_exceeded", + "license_balance_threshold_reached", + ] + """The type of alert. This must be a valid alert type.""" + + balance_alert_status: Optional[List[BalanceAlertStatus]] = None + """The current status of the alert. + + This field is only present for credit balance alerts. + """ + + grouping_keys: Optional[List[str]] = None + """The property keys to group cost alerts by. + + Only present for cost alerts with grouping enabled. + """ + + license_type: Optional[LicenseType] = None + """Minified license type for alert serialization.""" + + price_filters: Optional[List[PriceFilter]] = None + """Filters scoping which prices are included in grouped cost alert evaluation.""" + + threshold_overrides: Optional[List[ThresholdOverride]] = None + """Per-group threshold overrides. + + Each override maps a specific combination of grouping_keys values to a + replacement threshold list. Only present for grouped cost alerts that have at + least one override. + """ diff --git a/src/orb/types/alert_create_for_customer_params.py b/src/orb/types/alert_create_for_customer_params.py new file mode 100644 index 00000000..5503697d --- /dev/null +++ b/src/orb/types/alert_create_for_customer_params.py @@ -0,0 +1,21 @@ +# 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 + +from .threshold_param import ThresholdParam + +__all__ = ["AlertCreateForCustomerParams"] + + +class AlertCreateForCustomerParams(TypedDict, total=False): + currency: Required[str] + """The case sensitive currency or custom pricing unit to use for this alert.""" + + type: Required[Literal["credit_balance_depleted", "credit_balance_dropped", "credit_balance_recovered"]] + """The type of alert to create. This must be a valid alert type.""" + + thresholds: Optional[Iterable[ThresholdParam]] + """The thresholds that define the values at which the alert will be triggered.""" diff --git a/src/orb/types/alert_create_for_external_customer_params.py b/src/orb/types/alert_create_for_external_customer_params.py new file mode 100644 index 00000000..ddca21e5 --- /dev/null +++ b/src/orb/types/alert_create_for_external_customer_params.py @@ -0,0 +1,21 @@ +# 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 + +from .threshold_param import ThresholdParam + +__all__ = ["AlertCreateForExternalCustomerParams"] + + +class AlertCreateForExternalCustomerParams(TypedDict, total=False): + currency: Required[str] + """The case sensitive currency or custom pricing unit to use for this alert.""" + + type: Required[Literal["credit_balance_depleted", "credit_balance_dropped", "credit_balance_recovered"]] + """The type of alert to create. This must be a valid alert type.""" + + thresholds: Optional[Iterable[ThresholdParam]] + """The thresholds that define the values at which the alert will be triggered.""" diff --git a/src/orb/types/alert_create_for_subscription_params.py b/src/orb/types/alert_create_for_subscription_params.py new file mode 100644 index 00000000..090feb60 --- /dev/null +++ b/src/orb/types/alert_create_for_subscription_params.py @@ -0,0 +1,83 @@ +# 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 + +from .._types import SequenceNotStr +from .threshold_param import ThresholdParam + +__all__ = ["AlertCreateForSubscriptionParams", "PriceFilter", "ThresholdOverride"] + + +class AlertCreateForSubscriptionParams(TypedDict, total=False): + thresholds: Required[Iterable[ThresholdParam]] + """The thresholds that define the values at which the alert will be triggered.""" + + type: Required[Literal["usage_exceeded", "cost_exceeded"]] + """The type of alert to create. This must be a valid alert type.""" + + currency: Optional[str] + """ + The case sensitive currency or custom pricing unit to use for grouped cost + alerts. Required when grouping_keys is set. + """ + + grouping_keys: Optional[SequenceNotStr[str]] + """The property keys to group cost alerts by. + + Only applicable for cost_exceeded alerts. + """ + + metric_id: Optional[str] + """The metric to track usage for.""" + + price_filters: Optional[Iterable[PriceFilter]] + """Filters to scope which prices are included in grouped cost alert evaluation. + + Supports filtering by price_id, item_id, or price_type with includes/excludes + operators. Only applicable when grouping_keys is set. + """ + + threshold_overrides: Optional[Iterable[ThresholdOverride]] + """Per-group threshold overrides. + + Each override maps a specific combination of grouping_keys values to a list of + thresholds that fully replaces the default thresholds for that group. An empty + thresholds list silences the group. Groups without an override use the default + thresholds. Only applicable when grouping_keys is set. + """ + + +class PriceFilter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class ThresholdOverride(TypedDict, total=False): + """Per-group threshold override on a grouped cost alert. + + - An empty `thresholds` list silences alerts for this group (never fires). + - A non-empty list fully replaces the default thresholds for this group. + """ + + group_values: Required[SequenceNotStr[str]] + """The values of the grouping keys that identify this group. + + The list length must match the alert's grouping_keys, and values appear in the + same order as grouping_keys. + """ + + thresholds: Required[Iterable[ThresholdParam]] + """The thresholds to apply to this group. + + An empty list silences alerts for this group. A non-empty list fully replaces + the default thresholds for this group. + """ diff --git a/src/orb/types/alert_disable_params.py b/src/orb/types/alert_disable_params.py new file mode 100644 index 00000000..dc4a9847 --- /dev/null +++ b/src/orb/types/alert_disable_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +__all__ = ["AlertDisableParams"] + + +class AlertDisableParams(TypedDict, total=False): + subscription_id: Optional[str] + """Used to update the status of a plan alert scoped to this subscription_id""" diff --git a/src/orb/types/alert_enable_params.py b/src/orb/types/alert_enable_params.py new file mode 100644 index 00000000..b607505a --- /dev/null +++ b/src/orb/types/alert_enable_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +__all__ = ["AlertEnableParams"] + + +class AlertEnableParams(TypedDict, total=False): + subscription_id: Optional[str] + """Used to update the status of a plan alert scoped to this subscription_id""" diff --git a/src/orb/types/alert_list_params.py b/src/orb/types/alert_list_params.py new file mode 100644 index 00000000..ccd37423 --- /dev/null +++ b/src/orb/types/alert_list_params.py @@ -0,0 +1,40 @@ +# 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 Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["AlertListParams"] + + +class AlertListParams(TypedDict, total=False): + created_at_gt: Annotated[Union[str, datetime, None], PropertyInfo(alias="created_at[gt]", format="iso8601")] + + created_at_gte: Annotated[Union[str, datetime, None], PropertyInfo(alias="created_at[gte]", format="iso8601")] + + created_at_lt: Annotated[Union[str, datetime, None], PropertyInfo(alias="created_at[lt]", format="iso8601")] + + created_at_lte: Annotated[Union[str, datetime, None], PropertyInfo(alias="created_at[lte]", format="iso8601")] + + cursor: Optional[str] + """Cursor for pagination. + + This can be populated by the `next_cursor` value returned from the initial + request. + """ + + customer_id: Optional[str] + """Fetch alerts scoped to this customer_id""" + + external_customer_id: Optional[str] + """Fetch alerts scoped to this external_customer_id""" + + limit: int + """The number of items to fetch. Defaults to 20.""" + + subscription_id: Optional[str] + """Fetch alerts scoped to this subscription_id""" diff --git a/src/orb/types/alert_update_params.py b/src/orb/types/alert_update_params.py new file mode 100644 index 00000000..859f9bf0 --- /dev/null +++ b/src/orb/types/alert_update_params.py @@ -0,0 +1,62 @@ +# 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 + +from .._types import SequenceNotStr +from .threshold_param import ThresholdParam + +__all__ = ["AlertUpdateParams", "PriceFilter", "ThresholdOverride"] + + +class AlertUpdateParams(TypedDict, total=False): + thresholds: Required[Iterable[ThresholdParam]] + """The thresholds that define the values at which the alert will be triggered.""" + + price_filters: Optional[Iterable[PriceFilter]] + """Replaces the price filters on a grouped cost alert; an empty list clears them. + + Only applicable to cost alerts with grouping_keys. Omit to leave unchanged. + """ + + threshold_overrides: Optional[Iterable[ThresholdOverride]] + """ + Replaces the per-group threshold overrides on a grouped cost alert; an empty + list clears them. Only applicable to cost alerts with grouping_keys. Omit to + leave unchanged. + """ + + +class PriceFilter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class ThresholdOverride(TypedDict, total=False): + """Per-group threshold override on a grouped cost alert. + + - An empty `thresholds` list silences alerts for this group (never fires). + - A non-empty list fully replaces the default thresholds for this group. + """ + + group_values: Required[SequenceNotStr[str]] + """The values of the grouping keys that identify this group. + + The list length must match the alert's grouping_keys, and values appear in the + same order as grouping_keys. + """ + + thresholds: Required[Iterable[ThresholdParam]] + """The thresholds to apply to this group. + + An empty list silences alerts for this group. A non-empty list fully replaces + the default thresholds for this group. + """ diff --git a/src/orb/types/beta/__init__.py b/src/orb/types/beta/__init__.py index 93068e59..fc94e24f 100644 --- a/src/orb/types/beta/__init__.py +++ b/src/orb/types/beta/__init__.py @@ -2,6 +2,9 @@ from __future__ import annotations -from .evaluate_price_group import EvaluatePriceGroup as EvaluatePriceGroup -from .price_evaluate_params import PriceEvaluateParams as PriceEvaluateParams -from .price_evaluate_response import PriceEvaluateResponse as PriceEvaluateResponse +from .external_plan_id_create_plan_version_params import ( + ExternalPlanIDCreatePlanVersionParams as ExternalPlanIDCreatePlanVersionParams, +) +from .external_plan_id_set_default_plan_version_params import ( + ExternalPlanIDSetDefaultPlanVersionParams as ExternalPlanIDSetDefaultPlanVersionParams, +) diff --git a/src/orb/types/beta/external_plan_id_create_plan_version_params.py b/src/orb/types/beta/external_plan_id_create_plan_version_params.py new file mode 100644 index 00000000..fc4df9fc --- /dev/null +++ b/src/orb/types/beta/external_plan_id_create_plan_version_params.py @@ -0,0 +1,2770 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..._types import SequenceNotStr +from ..shared_params.new_maximum import NewMaximum +from ..shared_params.new_minimum import NewMinimum +from ..shared_params.unit_config import UnitConfig +from ..shared_params.new_usage_discount import NewUsageDiscount +from ..shared_params.new_amount_discount import NewAmountDiscount +from ..shared_params.new_plan_bulk_price import NewPlanBulkPrice +from ..shared_params.new_plan_unit_price import NewPlanUnitPrice +from ..shared_params.new_allocation_price import NewAllocationPrice +from ..shared_params.new_plan_matrix_price import NewPlanMatrixPrice +from ..shared_params.new_plan_tiered_price import NewPlanTieredPrice +from ..shared_params.new_plan_package_price import NewPlanPackagePrice +from ..shared_params.new_percentage_discount import NewPercentageDiscount +from ..shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from ..shared_params.new_plan_grouped_tiered_price import NewPlanGroupedTieredPrice +from ..shared_params.new_plan_tiered_package_price import NewPlanTieredPackagePrice +from ..shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from ..shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from ..shared_params.new_plan_minimum_composite_price import NewPlanMinimumCompositePrice +from ..shared_params.new_plan_unit_with_percent_price import NewPlanUnitWithPercentPrice +from ..shared_params.new_plan_grouped_allocation_price import NewPlanGroupedAllocationPrice +from ..shared_params.new_plan_bulk_with_proration_price import NewPlanBulkWithProrationPrice +from ..shared_params.new_plan_tiered_with_minimum_price import NewPlanTieredWithMinimumPrice +from ..shared_params.new_plan_unit_with_proration_price import NewPlanUnitWithProrationPrice +from ..shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration +from ..shared_params.new_plan_grouped_tiered_package_price import NewPlanGroupedTieredPackagePrice +from ..shared_params.new_plan_matrix_with_allocation_price import NewPlanMatrixWithAllocationPrice +from ..shared_params.new_plan_threshold_total_amount_price import NewPlanThresholdTotalAmountPrice +from ..shared_params.new_plan_cumulative_grouped_bulk_price import NewPlanCumulativeGroupedBulkPrice +from ..shared_params.new_plan_package_with_allocation_price import NewPlanPackageWithAllocationPrice +from ..shared_params.new_plan_matrix_with_display_name_price import NewPlanMatrixWithDisplayNamePrice +from ..shared_params.new_plan_max_group_tiered_package_price import NewPlanMaxGroupTieredPackagePrice +from ..shared_params.new_plan_tiered_package_with_minimum_price import NewPlanTieredPackageWithMinimumPrice +from ..shared_params.new_plan_grouped_with_metered_minimum_price import NewPlanGroupedWithMeteredMinimumPrice +from ..shared_params.new_plan_grouped_with_prorated_minimum_price import NewPlanGroupedWithProratedMinimumPrice +from ..shared_params.new_plan_scalable_matrix_with_unit_pricing_price import NewPlanScalableMatrixWithUnitPricingPrice +from ..shared_params.new_plan_scalable_matrix_with_tiered_pricing_price import ( + NewPlanScalableMatrixWithTieredPricingPrice, +) + +__all__ = [ + "ExternalPlanIDCreatePlanVersionParams", + "AddAdjustment", + "AddAdjustmentAdjustment", + "AddAdjustmentAdjustmentNewTieredPercentageDiscount", + "AddAdjustmentAdjustmentNewTieredPercentageDiscountTier", + "AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter", + "AddPrice", + "AddPriceLicenseAllocationPrice", + "AddPriceLicenseAllocationPriceLicenseAllocation", + "AddPriceLicenseAllocationPriceConversionRateConfig", + "AddPricePrice", + "AddPricePriceNewPlanBulkWithFiltersPrice", + "AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig", + "AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter", + "AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier", + "AddPricePriceNewPlanBulkWithFiltersPriceConversionRateConfig", + "AddPricePriceNewPlanMatrixWithThresholdDiscountsPrice", + "AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig", + "AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue", + "AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup", + "AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig", + "AddPricePriceNewPlanTieredWithProrationPrice", + "AddPricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig", + "AddPricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier", + "AddPricePriceNewPlanTieredWithProrationPriceConversionRateConfig", + "AddPricePriceNewPlanGroupedWithMinMaxThresholdsPrice", + "AddPricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig", + "AddPricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig", + "AddPricePriceNewPlanCumulativeGroupedAllocationPrice", + "AddPricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig", + "AddPricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig", + "AddPricePriceNewPlanDailyCreditAllowancePrice", + "AddPricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig", + "AddPricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue", + "AddPricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig", + "AddPricePriceNewPlanMeteredAllowancePrice", + "AddPricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig", + "AddPricePriceNewPlanMeteredAllowancePriceConversionRateConfig", + "AddPricePriceNewPlanPercentCompositePrice", + "AddPricePriceNewPlanPercentCompositePricePercentConfig", + "AddPricePriceNewPlanPercentCompositePriceConversionRateConfig", + "AddPricePriceNewPlanEventOutputPrice", + "AddPricePriceNewPlanEventOutputPriceEventOutputConfig", + "AddPricePriceNewPlanEventOutputPriceConversionRateConfig", + "RemoveAdjustment", + "RemovePrice", + "ReplaceAdjustment", + "ReplaceAdjustmentAdjustment", + "ReplaceAdjustmentAdjustmentNewTieredPercentageDiscount", + "ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountTier", + "ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountFilter", + "ReplacePrice", + "ReplacePriceLicenseAllocationPrice", + "ReplacePriceLicenseAllocationPriceLicenseAllocation", + "ReplacePriceLicenseAllocationPriceConversionRateConfig", + "ReplacePricePrice", + "ReplacePricePriceNewPlanBulkWithFiltersPrice", + "ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig", + "ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter", + "ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier", + "ReplacePricePriceNewPlanBulkWithFiltersPriceConversionRateConfig", + "ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPrice", + "ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig", + "ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue", + "ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup", + "ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig", + "ReplacePricePriceNewPlanTieredWithProrationPrice", + "ReplacePricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig", + "ReplacePricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier", + "ReplacePricePriceNewPlanTieredWithProrationPriceConversionRateConfig", + "ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPrice", + "ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig", + "ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig", + "ReplacePricePriceNewPlanCumulativeGroupedAllocationPrice", + "ReplacePricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig", + "ReplacePricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig", + "ReplacePricePriceNewPlanDailyCreditAllowancePrice", + "ReplacePricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig", + "ReplacePricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue", + "ReplacePricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig", + "ReplacePricePriceNewPlanMeteredAllowancePrice", + "ReplacePricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig", + "ReplacePricePriceNewPlanMeteredAllowancePriceConversionRateConfig", + "ReplacePricePriceNewPlanPercentCompositePrice", + "ReplacePricePriceNewPlanPercentCompositePricePercentConfig", + "ReplacePricePriceNewPlanPercentCompositePriceConversionRateConfig", + "ReplacePricePriceNewPlanEventOutputPrice", + "ReplacePricePriceNewPlanEventOutputPriceEventOutputConfig", + "ReplacePricePriceNewPlanEventOutputPriceConversionRateConfig", +] + + +class ExternalPlanIDCreatePlanVersionParams(TypedDict, total=False): + version: Required[int] + """New version number.""" + + add_adjustments: Optional[Iterable[AddAdjustment]] + """Additional adjustments to be added to the plan.""" + + add_prices: Optional[Iterable[AddPrice]] + """Additional prices to be added to the plan.""" + + remove_adjustments: Optional[Iterable[RemoveAdjustment]] + """Adjustments to be removed from the plan.""" + + remove_prices: Optional[Iterable[RemovePrice]] + """Prices to be removed from the plan.""" + + replace_adjustments: Optional[Iterable[ReplaceAdjustment]] + """Adjustments to be replaced with additional adjustments on the plan.""" + + replace_prices: Optional[Iterable[ReplacePrice]] + """Prices to be replaced with additional prices on the plan.""" + + set_as_default: Optional[bool] + """Set this new plan version as the default""" + + +class AddAdjustmentAdjustmentNewTieredPercentageDiscountTier(TypedDict, total=False): + lower_bound: Required[float] + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: Required[float] + """The percentage (0-1) discounted from spend in this tier.""" + + upper_bound: Optional[float] + """Inclusive upper bound of cumulative spend; null for the final open-ended tier.""" + + +class AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class AddAdjustmentAdjustmentNewTieredPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["tiered_percentage_discount"]] + + tiers: Required[Iterable[AddAdjustmentAdjustmentNewTieredPercentageDiscountTier]] + + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[Iterable[AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter]] + """A list of filters that determine which prices this adjustment will apply to.""" + + 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. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" + + +AddAdjustmentAdjustment: TypeAlias = Union[ + NewPercentageDiscount, + NewUsageDiscount, + NewAmountDiscount, + NewMinimum, + NewMaximum, + AddAdjustmentAdjustmentNewTieredPercentageDiscount, +] + + +class AddAdjustment(TypedDict, total=False): + adjustment: Required[AddAdjustmentAdjustment] + """The definition of a new adjustment to create and add to the plan.""" + + plan_phase_order: Optional[int] + """The phase to add this adjustment to.""" + + +class AddPriceLicenseAllocationPriceLicenseAllocation(TypedDict, total=False): + amount: Required[str] + """The amount of credits granted per active license per cadence.""" + + currency: Required[str] + """The currency of the license allocation.""" + + write_off_overage: Optional[bool] + """When True, overage beyond the allocation is written off.""" + + +AddPriceLicenseAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPriceLicenseAllocationPrice(TypedDict, total=False): + """The license allocation price to add to the plan.""" + + 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 price will be associated with.""" + + license_allocations: Required[Iterable[AddPriceLicenseAllocationPriceLicenseAllocation]] + """License allocations to associate with this price. + + Each entry defines a per-license credit pool granted each cadence. Requires + license_type_id or license_type_configuration to be set. + """ + + model_type: Required[Literal["unit"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_config: Required[UnitConfig] + """Configuration for unit pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPriceLicenseAllocationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter(TypedDict, total=False): + """Configuration for a single property filter""" + + property_key: Required[str] + """Event property key to filter on""" + + property_value: Required[str] + """Event property value to match""" + + +class AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier""" + + unit_amount: Required[str] + """Amount per unit""" + + tier_lower_bound: Optional[str] + """The lower bound for this tier""" + + +class AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig(TypedDict, total=False): + """Configuration for bulk_with_filters pricing""" + + filters: Required[Iterable[AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter]] + """Property filters to apply (all must match)""" + + tiers: Required[Iterable[AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +AddPricePriceNewPlanBulkWithFiltersPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanBulkWithFiltersPrice(TypedDict, total=False): + bulk_with_filters_config: Required[AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig] + """Configuration for bulk_with_filters pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk_with_filters"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanBulkWithFiltersPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue( + TypedDict, total=False +): + first_dimension_value: Required[str] + + unit_amount: Required[str] + + second_dimension_value: Optional[str] + + +class AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup( + TypedDict, total=False +): + above_threshold_discount_percentage: Required[str] + """Discount rate applied to spend above the threshold.""" + + below_threshold_discount_percentage: Required[str] + """Discount rate applied to spend at or below the threshold. + + Set to 0 for no baseline discount. + """ + + cell_coordinates: Required[str] + """Semicolon-separated list of matrix cell coordinates targeted by this group. + + Each coordinate is `first,second` when the matrix has two dimensions, or just + `first` for a single-dimension matrix. Example: `blue,circle;green,triangle`. + """ + + threshold_amount: Required[str] + + description: Optional[str] + + +class AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig(TypedDict, total=False): + """Configuration for matrix_with_threshold_discounts pricing""" + + default_unit_amount: Required[str] + """Unit price used for usage that does not match any defined matrix cell.""" + + first_dimension: Required[str] + """First matrix dimension key.""" + + matrix_values: Required[ + Iterable[AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue] + ] + """Per-cell unit prices.""" + + second_dimension: Optional[str] + """Optional second matrix dimension key.""" + + threshold_discount_groups: Iterable[ + AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup + ] + + +AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanMatrixWithThresholdDiscountsPrice(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 price will be associated with.""" + + matrix_with_threshold_discounts_config: Required[ + AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + ] + """Configuration for matrix_with_threshold_discounts pricing""" + + model_type: Required[Literal["matrix_with_threshold_discounts"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single tiered with proration tier""" + + tier_lower_bound: Required[str] + """Inclusive tier starting value""" + + unit_amount: Required[str] + """Amount per unit""" + + +class AddPricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig(TypedDict, total=False): + """Configuration for tiered_with_proration pricing""" + + tiers: Required[Iterable[AddPricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier]] + """ + Tiers for rating based on total usage quantities into the specified tier with + proration + """ + + +AddPricePriceNewPlanTieredWithProrationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanTieredWithProrationPrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered_with_proration"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_with_proration_config: Required[AddPricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig] + """Configuration for tiered_with_proration pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanTieredWithProrationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig(TypedDict, total=False): + """Configuration for grouped_with_min_max_thresholds pricing""" + + grouping_key: Required[str] + """The event property used to group before applying thresholds""" + + maximum_charge: Required[str] + """The maximum amount to charge each group""" + + minimum_charge: Required[str] + """The minimum amount to charge each group, regardless of usage""" + + per_unit_rate: Required[str] + """The base price charged per group""" + + +AddPricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanGroupedWithMinMaxThresholdsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_with_min_max_thresholds_config: Required[ + AddPricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + ] + """Configuration for grouped_with_min_max_thresholds pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_min_max_thresholds"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig(TypedDict, total=False): + """Configuration for cumulative_grouped_allocation pricing""" + + cumulative_allocation: Required[str] + """The overall allocation across all groups""" + + group_allocation: Required[str] + """The allocation per individual group""" + + grouping_key: Required[str] + """The event property used to group usage before applying allocations""" + + unit_amount: Required[str] + """The amount to charge for each unit outside of the allocation""" + + +AddPricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanCumulativeGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_allocation_config: Required[ + AddPricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + ] + """Configuration for cumulative_grouped_allocation pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue(TypedDict, total=False): + """Per-dimension credit price for the daily credit allowance model.""" + + dimension_values: Required[SequenceNotStr[Optional[str]]] + """One or two matrix keys to filter usage to this value by. + + For example, ["model"] could be used to apply a different credit rate to each AI + model. + """ + + unit_amount: Required[str] + """Credits charged per unit of usage matching the specified dimension_values""" + + +class AddPricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig(TypedDict, total=False): + """Configuration for daily_credit_allowance pricing""" + + daily_allowance: Required[str] + """Credits granted per day. Lose-it-or-use-it; does not roll over.""" + + default_unit_amount: Required[str] + """ + Default per-unit credit rate for any usage not bucketed into a specified + matrix_value + """ + + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" + + event_day_property: Required[str] + """Event property whose value identifies the day bucket the event belongs to (e.g. + + 'event_day' set to an ISO date string in the customer's timezone). The allowance + resets per distinct value of this property. + """ + + matrix_values: Required[ + Iterable[AddPricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue] + ] + """Per-dimension credit rates""" + + +AddPricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanDailyCreditAllowancePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + daily_credit_allowance_config: Required[AddPricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig] + """Configuration for daily_credit_allowance pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["daily_credit_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig(TypedDict, total=False): + """Configuration for metered_allowance pricing""" + + allowance_grouping_value: Required[str] + """ + The grouping_key value whose summed quantity represents the allowance for this + period (e.g. 'storage_snapshot' emitting 3 × avg storage). Capped at consumption + — credit can never exceed actual usage. + """ + + consumption_grouping_value: Required[str] + """The grouping_key value whose summed quantity represents consumption (e.g. + + 'download'). Charged at unit_amount. + """ + + grouping_key: Required[str] + """ + Event property used to partition the metric into consumption and allowance + quantities (e.g. 'event_name'). The metric is queried with this key and the two + values below select which partition is which. + """ + + unit_amount: Required[str] + """Per-unit price applied to gross consumption and to the allowance credit.""" + + allowance_display_name: str + """Sub-line label for the credit row (e.g. 'Up to 3x free egress').""" + + consumption_display_name: str + """Sub-line label for the gross consumption row (e.g. 'bytes gotten').""" + + +AddPricePriceNewPlanMeteredAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanMeteredAllowancePrice(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 price will be associated with.""" + + metered_allowance_config: Required[AddPricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig] + """Configuration for metered_allowance pricing""" + + model_type: Required[Literal["metered_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanMeteredAllowancePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanPercentCompositePricePercentConfig(TypedDict, total=False): + """Configuration for percent pricing""" + + percent: Required[float] + """Fraction of the component subtotals to charge (0 < percent <= 1).""" + + maximum_amount: Optional[str] + """Maximum amount to charge. If unset, the fee has no upper bound.""" + + minimum_amount: Optional[str] + """Minimum amount to charge. If unset, the fee is bounded below by 0.""" + + prorated: bool + """If true, the minimum_amount is prorated based on the service period. + + The maximum_amount is an absolute cap (never prorated), and the percent applied + to upstream subtotals is never prorated either. + """ + + +AddPricePriceNewPlanPercentCompositePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanPercentCompositePrice(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 price will be associated with.""" + + model_type: Required[Literal["percent"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + percent_config: Required[AddPricePriceNewPlanPercentCompositePricePercentConfig] + """Configuration for percent pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanPercentCompositePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanEventOutputPriceEventOutputConfig(TypedDict, total=False): + """Configuration for event_output pricing""" + + unit_rating_key: Required[str] + """The key in the event data to extract the unit rate from.""" + + default_unit_rate: Optional[str] + """ + If provided, this amount will be used as the unit rate when an event does not + have a value for the `unit_rating_key`. If not provided, events missing a unit + rate will be ignored. + """ + + grouping_key: Optional[str] + """An optional key in the event data to group by (e.g., event ID). + + All events will also be grouped by their unit rate. + """ + + +AddPricePriceNewPlanEventOutputPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanEventOutputPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + event_output_config: Required[AddPricePriceNewPlanEventOutputPriceEventOutputConfig] + """Configuration for event_output pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["event_output"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanEventOutputPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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[ + NewPlanUnitPrice, + NewPlanTieredPrice, + NewPlanBulkPrice, + AddPricePriceNewPlanBulkWithFiltersPrice, + NewPlanPackagePrice, + NewPlanMatrixPrice, + NewPlanThresholdTotalAmountPrice, + NewPlanTieredPackagePrice, + NewPlanTieredWithMinimumPrice, + NewPlanGroupedTieredPrice, + NewPlanTieredPackageWithMinimumPrice, + NewPlanPackageWithAllocationPrice, + NewPlanUnitWithPercentPrice, + NewPlanMatrixWithAllocationPrice, + AddPricePriceNewPlanMatrixWithThresholdDiscountsPrice, + AddPricePriceNewPlanTieredWithProrationPrice, + NewPlanUnitWithProrationPrice, + NewPlanGroupedAllocationPrice, + NewPlanBulkWithProrationPrice, + NewPlanGroupedWithProratedMinimumPrice, + NewPlanGroupedWithMeteredMinimumPrice, + AddPricePriceNewPlanGroupedWithMinMaxThresholdsPrice, + NewPlanMatrixWithDisplayNamePrice, + NewPlanGroupedTieredPackagePrice, + NewPlanMaxGroupTieredPackagePrice, + NewPlanScalableMatrixWithUnitPricingPrice, + NewPlanScalableMatrixWithTieredPricingPrice, + NewPlanCumulativeGroupedBulkPrice, + AddPricePriceNewPlanCumulativeGroupedAllocationPrice, + AddPricePriceNewPlanDailyCreditAllowancePrice, + AddPricePriceNewPlanMeteredAllowancePrice, + NewPlanMinimumCompositePrice, + AddPricePriceNewPlanPercentCompositePrice, + AddPricePriceNewPlanEventOutputPrice, +] + + +class AddPrice(TypedDict, total=False): + allocation_price: Optional[NewAllocationPrice] + """The allocation price to add to the plan.""" + + license_allocation_price: Optional[AddPriceLicenseAllocationPrice] + """The license allocation price to add to the plan.""" + + plan_phase_order: Optional[int] + """The phase to add this price to.""" + + price: Optional[AddPricePrice] + """New plan price request body params.""" + + +class RemoveAdjustment(TypedDict, total=False): + adjustment_id: Required[str] + """The id of the adjustment to remove from on the plan.""" + + plan_phase_order: Optional[int] + """The phase to remove this adjustment from.""" + + +class RemovePrice(TypedDict, total=False): + price_id: Required[str] + """The id of the price to remove from the plan.""" + + plan_phase_order: Optional[int] + """The phase to remove this price from.""" + + +class ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountTier(TypedDict, total=False): + lower_bound: Required[float] + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: Required[float] + """The percentage (0-1) discounted from spend in this tier.""" + + upper_bound: Optional[float] + """Inclusive upper bound of cumulative spend; null for the final open-ended tier.""" + + +class ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountFilter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class ReplaceAdjustmentAdjustmentNewTieredPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["tiered_percentage_discount"]] + + tiers: Required[Iterable[ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountTier]] + + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[Iterable[ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountFilter]] + """A list of filters that determine which prices this adjustment will apply to.""" + + 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. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" + + +ReplaceAdjustmentAdjustment: TypeAlias = Union[ + NewPercentageDiscount, + NewUsageDiscount, + NewAmountDiscount, + NewMinimum, + NewMaximum, + ReplaceAdjustmentAdjustmentNewTieredPercentageDiscount, +] + + +class ReplaceAdjustment(TypedDict, total=False): + adjustment: Required[ReplaceAdjustmentAdjustment] + """The definition of a new adjustment to create and add to the plan.""" + + replaces_adjustment_id: Required[str] + """The id of the adjustment on the plan to replace in the plan.""" + + plan_phase_order: Optional[int] + """The phase to replace this adjustment from.""" + + +class ReplacePriceLicenseAllocationPriceLicenseAllocation(TypedDict, total=False): + amount: Required[str] + """The amount of credits granted per active license per cadence.""" + + currency: Required[str] + """The currency of the license allocation.""" + + write_off_overage: Optional[bool] + """When True, overage beyond the allocation is written off.""" + + +ReplacePriceLicenseAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePriceLicenseAllocationPrice(TypedDict, total=False): + """The license allocation price to add to the plan.""" + + 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 price will be associated with.""" + + license_allocations: Required[Iterable[ReplacePriceLicenseAllocationPriceLicenseAllocation]] + """License allocations to associate with this price. + + Each entry defines a per-license credit pool granted each cadence. Requires + license_type_id or license_type_configuration to be set. + """ + + model_type: Required[Literal["unit"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_config: Required[UnitConfig] + """Configuration for unit pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePriceLicenseAllocationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter(TypedDict, total=False): + """Configuration for a single property filter""" + + property_key: Required[str] + """Event property key to filter on""" + + property_value: Required[str] + """Event property value to match""" + + +class ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier""" + + unit_amount: Required[str] + """Amount per unit""" + + tier_lower_bound: Optional[str] + """The lower bound for this tier""" + + +class ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig(TypedDict, total=False): + """Configuration for bulk_with_filters pricing""" + + filters: Required[Iterable[ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter]] + """Property filters to apply (all must match)""" + + tiers: Required[Iterable[ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +ReplacePricePriceNewPlanBulkWithFiltersPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanBulkWithFiltersPrice(TypedDict, total=False): + bulk_with_filters_config: Required[ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig] + """Configuration for bulk_with_filters pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk_with_filters"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanBulkWithFiltersPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue( + TypedDict, total=False +): + first_dimension_value: Required[str] + + unit_amount: Required[str] + + second_dimension_value: Optional[str] + + +class ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup( + TypedDict, total=False +): + above_threshold_discount_percentage: Required[str] + """Discount rate applied to spend above the threshold.""" + + below_threshold_discount_percentage: Required[str] + """Discount rate applied to spend at or below the threshold. + + Set to 0 for no baseline discount. + """ + + cell_coordinates: Required[str] + """Semicolon-separated list of matrix cell coordinates targeted by this group. + + Each coordinate is `first,second` when the matrix has two dimensions, or just + `first` for a single-dimension matrix. Example: `blue,circle;green,triangle`. + """ + + threshold_amount: Required[str] + + description: Optional[str] + + +class ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig( + TypedDict, total=False +): + """Configuration for matrix_with_threshold_discounts pricing""" + + default_unit_amount: Required[str] + """Unit price used for usage that does not match any defined matrix cell.""" + + first_dimension: Required[str] + """First matrix dimension key.""" + + matrix_values: Required[ + Iterable[ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue] + ] + """Per-cell unit prices.""" + + second_dimension: Optional[str] + """Optional second matrix dimension key.""" + + threshold_discount_groups: Iterable[ + ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup + ] + + +ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPrice(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 price will be associated with.""" + + matrix_with_threshold_discounts_config: Required[ + ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + ] + """Configuration for matrix_with_threshold_discounts pricing""" + + model_type: Required[Literal["matrix_with_threshold_discounts"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single tiered with proration tier""" + + tier_lower_bound: Required[str] + """Inclusive tier starting value""" + + unit_amount: Required[str] + """Amount per unit""" + + +class ReplacePricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig(TypedDict, total=False): + """Configuration for tiered_with_proration pricing""" + + tiers: Required[Iterable[ReplacePricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier]] + """ + Tiers for rating based on total usage quantities into the specified tier with + proration + """ + + +ReplacePricePriceNewPlanTieredWithProrationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanTieredWithProrationPrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered_with_proration"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_with_proration_config: Required[ReplacePricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig] + """Configuration for tiered_with_proration pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanTieredWithProrationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig(TypedDict, total=False): + """Configuration for grouped_with_min_max_thresholds pricing""" + + grouping_key: Required[str] + """The event property used to group before applying thresholds""" + + maximum_charge: Required[str] + """The maximum amount to charge each group""" + + minimum_charge: Required[str] + """The minimum amount to charge each group, regardless of usage""" + + per_unit_rate: Required[str] + """The base price charged per group""" + + +ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_with_min_max_thresholds_config: Required[ + ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + ] + """Configuration for grouped_with_min_max_thresholds pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_min_max_thresholds"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig(TypedDict, total=False): + """Configuration for cumulative_grouped_allocation pricing""" + + cumulative_allocation: Required[str] + """The overall allocation across all groups""" + + group_allocation: Required[str] + """The allocation per individual group""" + + grouping_key: Required[str] + """The event property used to group usage before applying allocations""" + + unit_amount: Required[str] + """The amount to charge for each unit outside of the allocation""" + + +ReplacePricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanCumulativeGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_allocation_config: Required[ + ReplacePricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + ] + """Configuration for cumulative_grouped_allocation pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue(TypedDict, total=False): + """Per-dimension credit price for the daily credit allowance model.""" + + dimension_values: Required[SequenceNotStr[Optional[str]]] + """One or two matrix keys to filter usage to this value by. + + For example, ["model"] could be used to apply a different credit rate to each AI + model. + """ + + unit_amount: Required[str] + """Credits charged per unit of usage matching the specified dimension_values""" + + +class ReplacePricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig(TypedDict, total=False): + """Configuration for daily_credit_allowance pricing""" + + daily_allowance: Required[str] + """Credits granted per day. Lose-it-or-use-it; does not roll over.""" + + default_unit_amount: Required[str] + """ + Default per-unit credit rate for any usage not bucketed into a specified + matrix_value + """ + + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" + + event_day_property: Required[str] + """Event property whose value identifies the day bucket the event belongs to (e.g. + + 'event_day' set to an ISO date string in the customer's timezone). The allowance + resets per distinct value of this property. + """ + + matrix_values: Required[ + Iterable[ReplacePricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue] + ] + """Per-dimension credit rates""" + + +ReplacePricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanDailyCreditAllowancePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + daily_credit_allowance_config: Required[ReplacePricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig] + """Configuration for daily_credit_allowance pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["daily_credit_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig(TypedDict, total=False): + """Configuration for metered_allowance pricing""" + + allowance_grouping_value: Required[str] + """ + The grouping_key value whose summed quantity represents the allowance for this + period (e.g. 'storage_snapshot' emitting 3 × avg storage). Capped at consumption + — credit can never exceed actual usage. + """ + + consumption_grouping_value: Required[str] + """The grouping_key value whose summed quantity represents consumption (e.g. + + 'download'). Charged at unit_amount. + """ + + grouping_key: Required[str] + """ + Event property used to partition the metric into consumption and allowance + quantities (e.g. 'event_name'). The metric is queried with this key and the two + values below select which partition is which. + """ + + unit_amount: Required[str] + """Per-unit price applied to gross consumption and to the allowance credit.""" + + allowance_display_name: str + """Sub-line label for the credit row (e.g. 'Up to 3x free egress').""" + + consumption_display_name: str + """Sub-line label for the gross consumption row (e.g. 'bytes gotten').""" + + +ReplacePricePriceNewPlanMeteredAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanMeteredAllowancePrice(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 price will be associated with.""" + + metered_allowance_config: Required[ReplacePricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig] + """Configuration for metered_allowance pricing""" + + model_type: Required[Literal["metered_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanMeteredAllowancePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanPercentCompositePricePercentConfig(TypedDict, total=False): + """Configuration for percent pricing""" + + percent: Required[float] + """Fraction of the component subtotals to charge (0 < percent <= 1).""" + + maximum_amount: Optional[str] + """Maximum amount to charge. If unset, the fee has no upper bound.""" + + minimum_amount: Optional[str] + """Minimum amount to charge. If unset, the fee is bounded below by 0.""" + + prorated: bool + """If true, the minimum_amount is prorated based on the service period. + + The maximum_amount is an absolute cap (never prorated), and the percent applied + to upstream subtotals is never prorated either. + """ + + +ReplacePricePriceNewPlanPercentCompositePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanPercentCompositePrice(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 price will be associated with.""" + + model_type: Required[Literal["percent"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + percent_config: Required[ReplacePricePriceNewPlanPercentCompositePricePercentConfig] + """Configuration for percent pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanPercentCompositePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanEventOutputPriceEventOutputConfig(TypedDict, total=False): + """Configuration for event_output pricing""" + + unit_rating_key: Required[str] + """The key in the event data to extract the unit rate from.""" + + default_unit_rate: Optional[str] + """ + If provided, this amount will be used as the unit rate when an event does not + have a value for the `unit_rating_key`. If not provided, events missing a unit + rate will be ignored. + """ + + grouping_key: Optional[str] + """An optional key in the event data to group by (e.g., event ID). + + All events will also be grouped by their unit rate. + """ + + +ReplacePricePriceNewPlanEventOutputPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanEventOutputPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + event_output_config: Required[ReplacePricePriceNewPlanEventOutputPriceEventOutputConfig] + """Configuration for event_output pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["event_output"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanEventOutputPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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[ + NewPlanUnitPrice, + NewPlanTieredPrice, + NewPlanBulkPrice, + ReplacePricePriceNewPlanBulkWithFiltersPrice, + NewPlanPackagePrice, + NewPlanMatrixPrice, + NewPlanThresholdTotalAmountPrice, + NewPlanTieredPackagePrice, + NewPlanTieredWithMinimumPrice, + NewPlanGroupedTieredPrice, + NewPlanTieredPackageWithMinimumPrice, + NewPlanPackageWithAllocationPrice, + NewPlanUnitWithPercentPrice, + NewPlanMatrixWithAllocationPrice, + ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPrice, + ReplacePricePriceNewPlanTieredWithProrationPrice, + NewPlanUnitWithProrationPrice, + NewPlanGroupedAllocationPrice, + NewPlanBulkWithProrationPrice, + NewPlanGroupedWithProratedMinimumPrice, + NewPlanGroupedWithMeteredMinimumPrice, + ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPrice, + NewPlanMatrixWithDisplayNamePrice, + NewPlanGroupedTieredPackagePrice, + NewPlanMaxGroupTieredPackagePrice, + NewPlanScalableMatrixWithUnitPricingPrice, + NewPlanScalableMatrixWithTieredPricingPrice, + NewPlanCumulativeGroupedBulkPrice, + ReplacePricePriceNewPlanCumulativeGroupedAllocationPrice, + ReplacePricePriceNewPlanDailyCreditAllowancePrice, + ReplacePricePriceNewPlanMeteredAllowancePrice, + NewPlanMinimumCompositePrice, + ReplacePricePriceNewPlanPercentCompositePrice, + ReplacePricePriceNewPlanEventOutputPrice, +] + + +class ReplacePrice(TypedDict, total=False): + replaces_price_id: Required[str] + """The id of the price on the plan to replace in the plan.""" + + allocation_price: Optional[NewAllocationPrice] + """The allocation price to add to the plan.""" + + license_allocation_price: Optional[ReplacePriceLicenseAllocationPrice] + """The license allocation price to add to the plan.""" + + plan_phase_order: Optional[int] + """The phase to replace this price from.""" + + price: Optional[ReplacePricePrice] + """New plan price request body params.""" diff --git a/src/orb/types/beta/external_plan_id_set_default_plan_version_params.py b/src/orb/types/beta/external_plan_id_set_default_plan_version_params.py new file mode 100644 index 00000000..cc9e85f5 --- /dev/null +++ b/src/orb/types/beta/external_plan_id_set_default_plan_version_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ExternalPlanIDSetDefaultPlanVersionParams"] + + +class ExternalPlanIDSetDefaultPlanVersionParams(TypedDict, total=False): + version: Required[int] + """Plan version to set as the default.""" diff --git a/src/orb/types/beta_create_plan_version_params.py b/src/orb/types/beta_create_plan_version_params.py new file mode 100644 index 00000000..3d4f91fd --- /dev/null +++ b/src/orb/types/beta_create_plan_version_params.py @@ -0,0 +1,2770 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .shared_params.new_maximum import NewMaximum +from .shared_params.new_minimum import NewMinimum +from .shared_params.unit_config import UnitConfig +from .shared_params.new_usage_discount import NewUsageDiscount +from .shared_params.new_amount_discount import NewAmountDiscount +from .shared_params.new_plan_bulk_price import NewPlanBulkPrice +from .shared_params.new_plan_unit_price import NewPlanUnitPrice +from .shared_params.new_allocation_price import NewAllocationPrice +from .shared_params.new_plan_matrix_price import NewPlanMatrixPrice +from .shared_params.new_plan_tiered_price import NewPlanTieredPrice +from .shared_params.new_plan_package_price import NewPlanPackagePrice +from .shared_params.new_percentage_discount import NewPercentageDiscount +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.new_plan_grouped_tiered_price import NewPlanGroupedTieredPrice +from .shared_params.new_plan_tiered_package_price import NewPlanTieredPackagePrice +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_plan_minimum_composite_price import NewPlanMinimumCompositePrice +from .shared_params.new_plan_unit_with_percent_price import NewPlanUnitWithPercentPrice +from .shared_params.new_plan_grouped_allocation_price import NewPlanGroupedAllocationPrice +from .shared_params.new_plan_bulk_with_proration_price import NewPlanBulkWithProrationPrice +from .shared_params.new_plan_tiered_with_minimum_price import NewPlanTieredWithMinimumPrice +from .shared_params.new_plan_unit_with_proration_price import NewPlanUnitWithProrationPrice +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration +from .shared_params.new_plan_grouped_tiered_package_price import NewPlanGroupedTieredPackagePrice +from .shared_params.new_plan_matrix_with_allocation_price import NewPlanMatrixWithAllocationPrice +from .shared_params.new_plan_threshold_total_amount_price import NewPlanThresholdTotalAmountPrice +from .shared_params.new_plan_cumulative_grouped_bulk_price import NewPlanCumulativeGroupedBulkPrice +from .shared_params.new_plan_package_with_allocation_price import NewPlanPackageWithAllocationPrice +from .shared_params.new_plan_matrix_with_display_name_price import NewPlanMatrixWithDisplayNamePrice +from .shared_params.new_plan_max_group_tiered_package_price import NewPlanMaxGroupTieredPackagePrice +from .shared_params.new_plan_tiered_package_with_minimum_price import NewPlanTieredPackageWithMinimumPrice +from .shared_params.new_plan_grouped_with_metered_minimum_price import NewPlanGroupedWithMeteredMinimumPrice +from .shared_params.new_plan_grouped_with_prorated_minimum_price import NewPlanGroupedWithProratedMinimumPrice +from .shared_params.new_plan_scalable_matrix_with_unit_pricing_price import NewPlanScalableMatrixWithUnitPricingPrice +from .shared_params.new_plan_scalable_matrix_with_tiered_pricing_price import ( + NewPlanScalableMatrixWithTieredPricingPrice, +) + +__all__ = [ + "BetaCreatePlanVersionParams", + "AddAdjustment", + "AddAdjustmentAdjustment", + "AddAdjustmentAdjustmentNewTieredPercentageDiscount", + "AddAdjustmentAdjustmentNewTieredPercentageDiscountTier", + "AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter", + "AddPrice", + "AddPriceLicenseAllocationPrice", + "AddPriceLicenseAllocationPriceLicenseAllocation", + "AddPriceLicenseAllocationPriceConversionRateConfig", + "AddPricePrice", + "AddPricePriceNewPlanBulkWithFiltersPrice", + "AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig", + "AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter", + "AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier", + "AddPricePriceNewPlanBulkWithFiltersPriceConversionRateConfig", + "AddPricePriceNewPlanMatrixWithThresholdDiscountsPrice", + "AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig", + "AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue", + "AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup", + "AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig", + "AddPricePriceNewPlanTieredWithProrationPrice", + "AddPricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig", + "AddPricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier", + "AddPricePriceNewPlanTieredWithProrationPriceConversionRateConfig", + "AddPricePriceNewPlanGroupedWithMinMaxThresholdsPrice", + "AddPricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig", + "AddPricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig", + "AddPricePriceNewPlanCumulativeGroupedAllocationPrice", + "AddPricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig", + "AddPricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig", + "AddPricePriceNewPlanDailyCreditAllowancePrice", + "AddPricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig", + "AddPricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue", + "AddPricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig", + "AddPricePriceNewPlanMeteredAllowancePrice", + "AddPricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig", + "AddPricePriceNewPlanMeteredAllowancePriceConversionRateConfig", + "AddPricePriceNewPlanPercentCompositePrice", + "AddPricePriceNewPlanPercentCompositePricePercentConfig", + "AddPricePriceNewPlanPercentCompositePriceConversionRateConfig", + "AddPricePriceNewPlanEventOutputPrice", + "AddPricePriceNewPlanEventOutputPriceEventOutputConfig", + "AddPricePriceNewPlanEventOutputPriceConversionRateConfig", + "RemoveAdjustment", + "RemovePrice", + "ReplaceAdjustment", + "ReplaceAdjustmentAdjustment", + "ReplaceAdjustmentAdjustmentNewTieredPercentageDiscount", + "ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountTier", + "ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountFilter", + "ReplacePrice", + "ReplacePriceLicenseAllocationPrice", + "ReplacePriceLicenseAllocationPriceLicenseAllocation", + "ReplacePriceLicenseAllocationPriceConversionRateConfig", + "ReplacePricePrice", + "ReplacePricePriceNewPlanBulkWithFiltersPrice", + "ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig", + "ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter", + "ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier", + "ReplacePricePriceNewPlanBulkWithFiltersPriceConversionRateConfig", + "ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPrice", + "ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig", + "ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue", + "ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup", + "ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig", + "ReplacePricePriceNewPlanTieredWithProrationPrice", + "ReplacePricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig", + "ReplacePricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier", + "ReplacePricePriceNewPlanTieredWithProrationPriceConversionRateConfig", + "ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPrice", + "ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig", + "ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig", + "ReplacePricePriceNewPlanCumulativeGroupedAllocationPrice", + "ReplacePricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig", + "ReplacePricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig", + "ReplacePricePriceNewPlanDailyCreditAllowancePrice", + "ReplacePricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig", + "ReplacePricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue", + "ReplacePricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig", + "ReplacePricePriceNewPlanMeteredAllowancePrice", + "ReplacePricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig", + "ReplacePricePriceNewPlanMeteredAllowancePriceConversionRateConfig", + "ReplacePricePriceNewPlanPercentCompositePrice", + "ReplacePricePriceNewPlanPercentCompositePricePercentConfig", + "ReplacePricePriceNewPlanPercentCompositePriceConversionRateConfig", + "ReplacePricePriceNewPlanEventOutputPrice", + "ReplacePricePriceNewPlanEventOutputPriceEventOutputConfig", + "ReplacePricePriceNewPlanEventOutputPriceConversionRateConfig", +] + + +class BetaCreatePlanVersionParams(TypedDict, total=False): + version: Required[int] + """New version number.""" + + add_adjustments: Optional[Iterable[AddAdjustment]] + """Additional adjustments to be added to the plan.""" + + add_prices: Optional[Iterable[AddPrice]] + """Additional prices to be added to the plan.""" + + remove_adjustments: Optional[Iterable[RemoveAdjustment]] + """Adjustments to be removed from the plan.""" + + remove_prices: Optional[Iterable[RemovePrice]] + """Prices to be removed from the plan.""" + + replace_adjustments: Optional[Iterable[ReplaceAdjustment]] + """Adjustments to be replaced with additional adjustments on the plan.""" + + replace_prices: Optional[Iterable[ReplacePrice]] + """Prices to be replaced with additional prices on the plan.""" + + set_as_default: Optional[bool] + """Set this new plan version as the default""" + + +class AddAdjustmentAdjustmentNewTieredPercentageDiscountTier(TypedDict, total=False): + lower_bound: Required[float] + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: Required[float] + """The percentage (0-1) discounted from spend in this tier.""" + + upper_bound: Optional[float] + """Inclusive upper bound of cumulative spend; null for the final open-ended tier.""" + + +class AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class AddAdjustmentAdjustmentNewTieredPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["tiered_percentage_discount"]] + + tiers: Required[Iterable[AddAdjustmentAdjustmentNewTieredPercentageDiscountTier]] + + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[Iterable[AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter]] + """A list of filters that determine which prices this adjustment will apply to.""" + + 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. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" + + +AddAdjustmentAdjustment: TypeAlias = Union[ + NewPercentageDiscount, + NewUsageDiscount, + NewAmountDiscount, + NewMinimum, + NewMaximum, + AddAdjustmentAdjustmentNewTieredPercentageDiscount, +] + + +class AddAdjustment(TypedDict, total=False): + adjustment: Required[AddAdjustmentAdjustment] + """The definition of a new adjustment to create and add to the plan.""" + + plan_phase_order: Optional[int] + """The phase to add this adjustment to.""" + + +class AddPriceLicenseAllocationPriceLicenseAllocation(TypedDict, total=False): + amount: Required[str] + """The amount of credits granted per active license per cadence.""" + + currency: Required[str] + """The currency of the license allocation.""" + + write_off_overage: Optional[bool] + """When True, overage beyond the allocation is written off.""" + + +AddPriceLicenseAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPriceLicenseAllocationPrice(TypedDict, total=False): + """The license allocation price to add to the plan.""" + + 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 price will be associated with.""" + + license_allocations: Required[Iterable[AddPriceLicenseAllocationPriceLicenseAllocation]] + """License allocations to associate with this price. + + Each entry defines a per-license credit pool granted each cadence. Requires + license_type_id or license_type_configuration to be set. + """ + + model_type: Required[Literal["unit"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_config: Required[UnitConfig] + """Configuration for unit pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPriceLicenseAllocationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter(TypedDict, total=False): + """Configuration for a single property filter""" + + property_key: Required[str] + """Event property key to filter on""" + + property_value: Required[str] + """Event property value to match""" + + +class AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier""" + + unit_amount: Required[str] + """Amount per unit""" + + tier_lower_bound: Optional[str] + """The lower bound for this tier""" + + +class AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig(TypedDict, total=False): + """Configuration for bulk_with_filters pricing""" + + filters: Required[Iterable[AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter]] + """Property filters to apply (all must match)""" + + tiers: Required[Iterable[AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +AddPricePriceNewPlanBulkWithFiltersPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanBulkWithFiltersPrice(TypedDict, total=False): + bulk_with_filters_config: Required[AddPricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig] + """Configuration for bulk_with_filters pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk_with_filters"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanBulkWithFiltersPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue( + TypedDict, total=False +): + first_dimension_value: Required[str] + + unit_amount: Required[str] + + second_dimension_value: Optional[str] + + +class AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup( + TypedDict, total=False +): + above_threshold_discount_percentage: Required[str] + """Discount rate applied to spend above the threshold.""" + + below_threshold_discount_percentage: Required[str] + """Discount rate applied to spend at or below the threshold. + + Set to 0 for no baseline discount. + """ + + cell_coordinates: Required[str] + """Semicolon-separated list of matrix cell coordinates targeted by this group. + + Each coordinate is `first,second` when the matrix has two dimensions, or just + `first` for a single-dimension matrix. Example: `blue,circle;green,triangle`. + """ + + threshold_amount: Required[str] + + description: Optional[str] + + +class AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig(TypedDict, total=False): + """Configuration for matrix_with_threshold_discounts pricing""" + + default_unit_amount: Required[str] + """Unit price used for usage that does not match any defined matrix cell.""" + + first_dimension: Required[str] + """First matrix dimension key.""" + + matrix_values: Required[ + Iterable[AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue] + ] + """Per-cell unit prices.""" + + second_dimension: Optional[str] + """Optional second matrix dimension key.""" + + threshold_discount_groups: Iterable[ + AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup + ] + + +AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanMatrixWithThresholdDiscountsPrice(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 price will be associated with.""" + + matrix_with_threshold_discounts_config: Required[ + AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + ] + """Configuration for matrix_with_threshold_discounts pricing""" + + model_type: Required[Literal["matrix_with_threshold_discounts"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single tiered with proration tier""" + + tier_lower_bound: Required[str] + """Inclusive tier starting value""" + + unit_amount: Required[str] + """Amount per unit""" + + +class AddPricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig(TypedDict, total=False): + """Configuration for tiered_with_proration pricing""" + + tiers: Required[Iterable[AddPricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier]] + """ + Tiers for rating based on total usage quantities into the specified tier with + proration + """ + + +AddPricePriceNewPlanTieredWithProrationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanTieredWithProrationPrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered_with_proration"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_with_proration_config: Required[AddPricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig] + """Configuration for tiered_with_proration pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanTieredWithProrationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig(TypedDict, total=False): + """Configuration for grouped_with_min_max_thresholds pricing""" + + grouping_key: Required[str] + """The event property used to group before applying thresholds""" + + maximum_charge: Required[str] + """The maximum amount to charge each group""" + + minimum_charge: Required[str] + """The minimum amount to charge each group, regardless of usage""" + + per_unit_rate: Required[str] + """The base price charged per group""" + + +AddPricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanGroupedWithMinMaxThresholdsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_with_min_max_thresholds_config: Required[ + AddPricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + ] + """Configuration for grouped_with_min_max_thresholds pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_min_max_thresholds"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig(TypedDict, total=False): + """Configuration for cumulative_grouped_allocation pricing""" + + cumulative_allocation: Required[str] + """The overall allocation across all groups""" + + group_allocation: Required[str] + """The allocation per individual group""" + + grouping_key: Required[str] + """The event property used to group usage before applying allocations""" + + unit_amount: Required[str] + """The amount to charge for each unit outside of the allocation""" + + +AddPricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanCumulativeGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_allocation_config: Required[ + AddPricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + ] + """Configuration for cumulative_grouped_allocation pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue(TypedDict, total=False): + """Per-dimension credit price for the daily credit allowance model.""" + + dimension_values: Required[SequenceNotStr[Optional[str]]] + """One or two matrix keys to filter usage to this value by. + + For example, ["model"] could be used to apply a different credit rate to each AI + model. + """ + + unit_amount: Required[str] + """Credits charged per unit of usage matching the specified dimension_values""" + + +class AddPricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig(TypedDict, total=False): + """Configuration for daily_credit_allowance pricing""" + + daily_allowance: Required[str] + """Credits granted per day. Lose-it-or-use-it; does not roll over.""" + + default_unit_amount: Required[str] + """ + Default per-unit credit rate for any usage not bucketed into a specified + matrix_value + """ + + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" + + event_day_property: Required[str] + """Event property whose value identifies the day bucket the event belongs to (e.g. + + 'event_day' set to an ISO date string in the customer's timezone). The allowance + resets per distinct value of this property. + """ + + matrix_values: Required[ + Iterable[AddPricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue] + ] + """Per-dimension credit rates""" + + +AddPricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanDailyCreditAllowancePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + daily_credit_allowance_config: Required[AddPricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig] + """Configuration for daily_credit_allowance pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["daily_credit_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig(TypedDict, total=False): + """Configuration for metered_allowance pricing""" + + allowance_grouping_value: Required[str] + """ + The grouping_key value whose summed quantity represents the allowance for this + period (e.g. 'storage_snapshot' emitting 3 × avg storage). Capped at consumption + — credit can never exceed actual usage. + """ + + consumption_grouping_value: Required[str] + """The grouping_key value whose summed quantity represents consumption (e.g. + + 'download'). Charged at unit_amount. + """ + + grouping_key: Required[str] + """ + Event property used to partition the metric into consumption and allowance + quantities (e.g. 'event_name'). The metric is queried with this key and the two + values below select which partition is which. + """ + + unit_amount: Required[str] + """Per-unit price applied to gross consumption and to the allowance credit.""" + + allowance_display_name: str + """Sub-line label for the credit row (e.g. 'Up to 3x free egress').""" + + consumption_display_name: str + """Sub-line label for the gross consumption row (e.g. 'bytes gotten').""" + + +AddPricePriceNewPlanMeteredAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanMeteredAllowancePrice(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 price will be associated with.""" + + metered_allowance_config: Required[AddPricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig] + """Configuration for metered_allowance pricing""" + + model_type: Required[Literal["metered_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanMeteredAllowancePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanPercentCompositePricePercentConfig(TypedDict, total=False): + """Configuration for percent pricing""" + + percent: Required[float] + """Fraction of the component subtotals to charge (0 < percent <= 1).""" + + maximum_amount: Optional[str] + """Maximum amount to charge. If unset, the fee has no upper bound.""" + + minimum_amount: Optional[str] + """Minimum amount to charge. If unset, the fee is bounded below by 0.""" + + prorated: bool + """If true, the minimum_amount is prorated based on the service period. + + The maximum_amount is an absolute cap (never prorated), and the percent applied + to upstream subtotals is never prorated either. + """ + + +AddPricePriceNewPlanPercentCompositePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanPercentCompositePrice(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 price will be associated with.""" + + model_type: Required[Literal["percent"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + percent_config: Required[AddPricePriceNewPlanPercentCompositePricePercentConfig] + """Configuration for percent pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanPercentCompositePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewPlanEventOutputPriceEventOutputConfig(TypedDict, total=False): + """Configuration for event_output pricing""" + + unit_rating_key: Required[str] + """The key in the event data to extract the unit rate from.""" + + default_unit_rate: Optional[str] + """ + If provided, this amount will be used as the unit rate when an event does not + have a value for the `unit_rating_key`. If not provided, events missing a unit + rate will be ignored. + """ + + grouping_key: Optional[str] + """An optional key in the event data to group by (e.g., event ID). + + All events will also be grouped by their unit rate. + """ + + +AddPricePriceNewPlanEventOutputPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewPlanEventOutputPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + event_output_config: Required[AddPricePriceNewPlanEventOutputPriceEventOutputConfig] + """Configuration for event_output pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["event_output"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewPlanEventOutputPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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[ + NewPlanUnitPrice, + NewPlanTieredPrice, + NewPlanBulkPrice, + AddPricePriceNewPlanBulkWithFiltersPrice, + NewPlanPackagePrice, + NewPlanMatrixPrice, + NewPlanThresholdTotalAmountPrice, + NewPlanTieredPackagePrice, + NewPlanTieredWithMinimumPrice, + NewPlanGroupedTieredPrice, + NewPlanTieredPackageWithMinimumPrice, + NewPlanPackageWithAllocationPrice, + NewPlanUnitWithPercentPrice, + NewPlanMatrixWithAllocationPrice, + AddPricePriceNewPlanMatrixWithThresholdDiscountsPrice, + AddPricePriceNewPlanTieredWithProrationPrice, + NewPlanUnitWithProrationPrice, + NewPlanGroupedAllocationPrice, + NewPlanBulkWithProrationPrice, + NewPlanGroupedWithProratedMinimumPrice, + NewPlanGroupedWithMeteredMinimumPrice, + AddPricePriceNewPlanGroupedWithMinMaxThresholdsPrice, + NewPlanMatrixWithDisplayNamePrice, + NewPlanGroupedTieredPackagePrice, + NewPlanMaxGroupTieredPackagePrice, + NewPlanScalableMatrixWithUnitPricingPrice, + NewPlanScalableMatrixWithTieredPricingPrice, + NewPlanCumulativeGroupedBulkPrice, + AddPricePriceNewPlanCumulativeGroupedAllocationPrice, + AddPricePriceNewPlanDailyCreditAllowancePrice, + AddPricePriceNewPlanMeteredAllowancePrice, + NewPlanMinimumCompositePrice, + AddPricePriceNewPlanPercentCompositePrice, + AddPricePriceNewPlanEventOutputPrice, +] + + +class AddPrice(TypedDict, total=False): + allocation_price: Optional[NewAllocationPrice] + """The allocation price to add to the plan.""" + + license_allocation_price: Optional[AddPriceLicenseAllocationPrice] + """The license allocation price to add to the plan.""" + + plan_phase_order: Optional[int] + """The phase to add this price to.""" + + price: Optional[AddPricePrice] + """New plan price request body params.""" + + +class RemoveAdjustment(TypedDict, total=False): + adjustment_id: Required[str] + """The id of the adjustment to remove from on the plan.""" + + plan_phase_order: Optional[int] + """The phase to remove this adjustment from.""" + + +class RemovePrice(TypedDict, total=False): + price_id: Required[str] + """The id of the price to remove from the plan.""" + + plan_phase_order: Optional[int] + """The phase to remove this price from.""" + + +class ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountTier(TypedDict, total=False): + lower_bound: Required[float] + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: Required[float] + """The percentage (0-1) discounted from spend in this tier.""" + + upper_bound: Optional[float] + """Inclusive upper bound of cumulative spend; null for the final open-ended tier.""" + + +class ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountFilter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class ReplaceAdjustmentAdjustmentNewTieredPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["tiered_percentage_discount"]] + + tiers: Required[Iterable[ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountTier]] + + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[Iterable[ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountFilter]] + """A list of filters that determine which prices this adjustment will apply to.""" + + 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. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" + + +ReplaceAdjustmentAdjustment: TypeAlias = Union[ + NewPercentageDiscount, + NewUsageDiscount, + NewAmountDiscount, + NewMinimum, + NewMaximum, + ReplaceAdjustmentAdjustmentNewTieredPercentageDiscount, +] + + +class ReplaceAdjustment(TypedDict, total=False): + adjustment: Required[ReplaceAdjustmentAdjustment] + """The definition of a new adjustment to create and add to the plan.""" + + replaces_adjustment_id: Required[str] + """The id of the adjustment on the plan to replace in the plan.""" + + plan_phase_order: Optional[int] + """The phase to replace this adjustment from.""" + + +class ReplacePriceLicenseAllocationPriceLicenseAllocation(TypedDict, total=False): + amount: Required[str] + """The amount of credits granted per active license per cadence.""" + + currency: Required[str] + """The currency of the license allocation.""" + + write_off_overage: Optional[bool] + """When True, overage beyond the allocation is written off.""" + + +ReplacePriceLicenseAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePriceLicenseAllocationPrice(TypedDict, total=False): + """The license allocation price to add to the plan.""" + + 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 price will be associated with.""" + + license_allocations: Required[Iterable[ReplacePriceLicenseAllocationPriceLicenseAllocation]] + """License allocations to associate with this price. + + Each entry defines a per-license credit pool granted each cadence. Requires + license_type_id or license_type_configuration to be set. + """ + + model_type: Required[Literal["unit"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_config: Required[UnitConfig] + """Configuration for unit pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePriceLicenseAllocationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter(TypedDict, total=False): + """Configuration for a single property filter""" + + property_key: Required[str] + """Event property key to filter on""" + + property_value: Required[str] + """Event property value to match""" + + +class ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier""" + + unit_amount: Required[str] + """Amount per unit""" + + tier_lower_bound: Optional[str] + """The lower bound for this tier""" + + +class ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig(TypedDict, total=False): + """Configuration for bulk_with_filters pricing""" + + filters: Required[Iterable[ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter]] + """Property filters to apply (all must match)""" + + tiers: Required[Iterable[ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +ReplacePricePriceNewPlanBulkWithFiltersPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanBulkWithFiltersPrice(TypedDict, total=False): + bulk_with_filters_config: Required[ReplacePricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig] + """Configuration for bulk_with_filters pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk_with_filters"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanBulkWithFiltersPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue( + TypedDict, total=False +): + first_dimension_value: Required[str] + + unit_amount: Required[str] + + second_dimension_value: Optional[str] + + +class ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup( + TypedDict, total=False +): + above_threshold_discount_percentage: Required[str] + """Discount rate applied to spend above the threshold.""" + + below_threshold_discount_percentage: Required[str] + """Discount rate applied to spend at or below the threshold. + + Set to 0 for no baseline discount. + """ + + cell_coordinates: Required[str] + """Semicolon-separated list of matrix cell coordinates targeted by this group. + + Each coordinate is `first,second` when the matrix has two dimensions, or just + `first` for a single-dimension matrix. Example: `blue,circle;green,triangle`. + """ + + threshold_amount: Required[str] + + description: Optional[str] + + +class ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig( + TypedDict, total=False +): + """Configuration for matrix_with_threshold_discounts pricing""" + + default_unit_amount: Required[str] + """Unit price used for usage that does not match any defined matrix cell.""" + + first_dimension: Required[str] + """First matrix dimension key.""" + + matrix_values: Required[ + Iterable[ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue] + ] + """Per-cell unit prices.""" + + second_dimension: Optional[str] + """Optional second matrix dimension key.""" + + threshold_discount_groups: Iterable[ + ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup + ] + + +ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPrice(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 price will be associated with.""" + + matrix_with_threshold_discounts_config: Required[ + ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + ] + """Configuration for matrix_with_threshold_discounts pricing""" + + model_type: Required[Literal["matrix_with_threshold_discounts"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single tiered with proration tier""" + + tier_lower_bound: Required[str] + """Inclusive tier starting value""" + + unit_amount: Required[str] + """Amount per unit""" + + +class ReplacePricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig(TypedDict, total=False): + """Configuration for tiered_with_proration pricing""" + + tiers: Required[Iterable[ReplacePricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier]] + """ + Tiers for rating based on total usage quantities into the specified tier with + proration + """ + + +ReplacePricePriceNewPlanTieredWithProrationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanTieredWithProrationPrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered_with_proration"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_with_proration_config: Required[ReplacePricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig] + """Configuration for tiered_with_proration pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanTieredWithProrationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig(TypedDict, total=False): + """Configuration for grouped_with_min_max_thresholds pricing""" + + grouping_key: Required[str] + """The event property used to group before applying thresholds""" + + maximum_charge: Required[str] + """The maximum amount to charge each group""" + + minimum_charge: Required[str] + """The minimum amount to charge each group, regardless of usage""" + + per_unit_rate: Required[str] + """The base price charged per group""" + + +ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_with_min_max_thresholds_config: Required[ + ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + ] + """Configuration for grouped_with_min_max_thresholds pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_min_max_thresholds"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig(TypedDict, total=False): + """Configuration for cumulative_grouped_allocation pricing""" + + cumulative_allocation: Required[str] + """The overall allocation across all groups""" + + group_allocation: Required[str] + """The allocation per individual group""" + + grouping_key: Required[str] + """The event property used to group usage before applying allocations""" + + unit_amount: Required[str] + """The amount to charge for each unit outside of the allocation""" + + +ReplacePricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanCumulativeGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_allocation_config: Required[ + ReplacePricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + ] + """Configuration for cumulative_grouped_allocation pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue(TypedDict, total=False): + """Per-dimension credit price for the daily credit allowance model.""" + + dimension_values: Required[SequenceNotStr[Optional[str]]] + """One or two matrix keys to filter usage to this value by. + + For example, ["model"] could be used to apply a different credit rate to each AI + model. + """ + + unit_amount: Required[str] + """Credits charged per unit of usage matching the specified dimension_values""" + + +class ReplacePricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig(TypedDict, total=False): + """Configuration for daily_credit_allowance pricing""" + + daily_allowance: Required[str] + """Credits granted per day. Lose-it-or-use-it; does not roll over.""" + + default_unit_amount: Required[str] + """ + Default per-unit credit rate for any usage not bucketed into a specified + matrix_value + """ + + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" + + event_day_property: Required[str] + """Event property whose value identifies the day bucket the event belongs to (e.g. + + 'event_day' set to an ISO date string in the customer's timezone). The allowance + resets per distinct value of this property. + """ + + matrix_values: Required[ + Iterable[ReplacePricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue] + ] + """Per-dimension credit rates""" + + +ReplacePricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanDailyCreditAllowancePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + daily_credit_allowance_config: Required[ReplacePricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig] + """Configuration for daily_credit_allowance pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["daily_credit_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig(TypedDict, total=False): + """Configuration for metered_allowance pricing""" + + allowance_grouping_value: Required[str] + """ + The grouping_key value whose summed quantity represents the allowance for this + period (e.g. 'storage_snapshot' emitting 3 × avg storage). Capped at consumption + — credit can never exceed actual usage. + """ + + consumption_grouping_value: Required[str] + """The grouping_key value whose summed quantity represents consumption (e.g. + + 'download'). Charged at unit_amount. + """ + + grouping_key: Required[str] + """ + Event property used to partition the metric into consumption and allowance + quantities (e.g. 'event_name'). The metric is queried with this key and the two + values below select which partition is which. + """ + + unit_amount: Required[str] + """Per-unit price applied to gross consumption and to the allowance credit.""" + + allowance_display_name: str + """Sub-line label for the credit row (e.g. 'Up to 3x free egress').""" + + consumption_display_name: str + """Sub-line label for the gross consumption row (e.g. 'bytes gotten').""" + + +ReplacePricePriceNewPlanMeteredAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanMeteredAllowancePrice(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 price will be associated with.""" + + metered_allowance_config: Required[ReplacePricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig] + """Configuration for metered_allowance pricing""" + + model_type: Required[Literal["metered_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanMeteredAllowancePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanPercentCompositePricePercentConfig(TypedDict, total=False): + """Configuration for percent pricing""" + + percent: Required[float] + """Fraction of the component subtotals to charge (0 < percent <= 1).""" + + maximum_amount: Optional[str] + """Maximum amount to charge. If unset, the fee has no upper bound.""" + + minimum_amount: Optional[str] + """Minimum amount to charge. If unset, the fee is bounded below by 0.""" + + prorated: bool + """If true, the minimum_amount is prorated based on the service period. + + The maximum_amount is an absolute cap (never prorated), and the percent applied + to upstream subtotals is never prorated either. + """ + + +ReplacePricePriceNewPlanPercentCompositePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanPercentCompositePrice(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 price will be associated with.""" + + model_type: Required[Literal["percent"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + percent_config: Required[ReplacePricePriceNewPlanPercentCompositePricePercentConfig] + """Configuration for percent pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanPercentCompositePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewPlanEventOutputPriceEventOutputConfig(TypedDict, total=False): + """Configuration for event_output pricing""" + + unit_rating_key: Required[str] + """The key in the event data to extract the unit rate from.""" + + default_unit_rate: Optional[str] + """ + If provided, this amount will be used as the unit rate when an event does not + have a value for the `unit_rating_key`. If not provided, events missing a unit + rate will be ignored. + """ + + grouping_key: Optional[str] + """An optional key in the event data to group by (e.g., event ID). + + All events will also be grouped by their unit rate. + """ + + +ReplacePricePriceNewPlanEventOutputPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewPlanEventOutputPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + event_output_config: Required[ReplacePricePriceNewPlanEventOutputPriceEventOutputConfig] + """Configuration for event_output pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["event_output"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewPlanEventOutputPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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[ + NewPlanUnitPrice, + NewPlanTieredPrice, + NewPlanBulkPrice, + ReplacePricePriceNewPlanBulkWithFiltersPrice, + NewPlanPackagePrice, + NewPlanMatrixPrice, + NewPlanThresholdTotalAmountPrice, + NewPlanTieredPackagePrice, + NewPlanTieredWithMinimumPrice, + NewPlanGroupedTieredPrice, + NewPlanTieredPackageWithMinimumPrice, + NewPlanPackageWithAllocationPrice, + NewPlanUnitWithPercentPrice, + NewPlanMatrixWithAllocationPrice, + ReplacePricePriceNewPlanMatrixWithThresholdDiscountsPrice, + ReplacePricePriceNewPlanTieredWithProrationPrice, + NewPlanUnitWithProrationPrice, + NewPlanGroupedAllocationPrice, + NewPlanBulkWithProrationPrice, + NewPlanGroupedWithProratedMinimumPrice, + NewPlanGroupedWithMeteredMinimumPrice, + ReplacePricePriceNewPlanGroupedWithMinMaxThresholdsPrice, + NewPlanMatrixWithDisplayNamePrice, + NewPlanGroupedTieredPackagePrice, + NewPlanMaxGroupTieredPackagePrice, + NewPlanScalableMatrixWithUnitPricingPrice, + NewPlanScalableMatrixWithTieredPricingPrice, + NewPlanCumulativeGroupedBulkPrice, + ReplacePricePriceNewPlanCumulativeGroupedAllocationPrice, + ReplacePricePriceNewPlanDailyCreditAllowancePrice, + ReplacePricePriceNewPlanMeteredAllowancePrice, + NewPlanMinimumCompositePrice, + ReplacePricePriceNewPlanPercentCompositePrice, + ReplacePricePriceNewPlanEventOutputPrice, +] + + +class ReplacePrice(TypedDict, total=False): + replaces_price_id: Required[str] + """The id of the price on the plan to replace in the plan.""" + + allocation_price: Optional[NewAllocationPrice] + """The allocation price to add to the plan.""" + + license_allocation_price: Optional[ReplacePriceLicenseAllocationPrice] + """The license allocation price to add to the plan.""" + + plan_phase_order: Optional[int] + """The phase to replace this price from.""" + + price: Optional[ReplacePricePrice] + """New plan price request body params.""" diff --git a/src/orb/types/beta_set_default_plan_version_params.py b/src/orb/types/beta_set_default_plan_version_params.py new file mode 100644 index 00000000..d9c61c7e --- /dev/null +++ b/src/orb/types/beta_set_default_plan_version_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BetaSetDefaultPlanVersionParams"] + + +class BetaSetDefaultPlanVersionParams(TypedDict, total=False): + version: Required[int] + """Plan version to set as the default.""" diff --git a/src/orb/types/metric_create_response.py b/src/orb/types/billable_metric.py similarity index 69% rename from src/orb/types/metric_create_response.py rename to src/orb/types/billable_metric.py index 2166f585..b3b6a158 100644 --- a/src/orb/types/metric_create_response.py +++ b/src/orb/types/billable_metric.py @@ -1,15 +1,20 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, Optional +from typing import Dict, List, Optional from typing_extensions import Literal from .item import Item from .._models import BaseModel -__all__ = ["MetricCreateResponse"] +__all__ = ["BillableMetric"] -class MetricCreateResponse(BaseModel): +class BillableMetric(BaseModel): + """ + The Metric resource represents a calculation of a quantity based on events. + Metrics are defined by the query that transforms raw usage events into meaningful values for your customers. + """ + id: str description: Optional[str] = None @@ -33,3 +38,5 @@ class MetricCreateResponse(BaseModel): name: str status: Literal["active", "draft", "archived"] + + parameter_definitions: Optional[List[Dict[str, object]]] = None diff --git a/src/orb/types/coupon.py b/src/orb/types/coupon.py index 7f8d5282..1e77708e 100644 --- a/src/orb/types/coupon.py +++ b/src/orb/types/coupon.py @@ -1,51 +1,24 @@ # 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 +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"] +Discount: TypeAlias = Annotated[Union[PercentageDiscount, AmountDiscount], PropertyInfo(discriminator="discount_type")] -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. +class Coupon(BaseModel): """ - - 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. + A coupon represents a reusable discount configuration that can be applied either as a fixed or percentage amount to an invoice or subscription. Coupons are activated using a redemption code, which applies the discount to a subscription or invoice. The duration of a coupon determines how long it remains available for use by end users. """ - discount_type: Literal["amount"] - - reason: Optional[str] = None - - -Discount = Union[DiscountPercentageDiscount, DiscountAmountDiscount] - - -class Coupon(BaseModel): id: str """Also referred to as coupon_id in this documentation.""" diff --git a/src/orb/types/coupon_create_params.py b/src/orb/types/coupon_create_params.py index a61bb3ff..50746cd1 100644 --- a/src/orb/types/coupon_create_params.py +++ b/src/orb/types/coupon_create_params.py @@ -2,10 +2,10 @@ from __future__ import annotations -from typing import List, Union, Optional -from typing_extensions import Literal, Required, TypedDict +from typing import Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict -__all__ = ["CouponCreateParams", "Discount", "DiscountPercentageDiscount", "DiscountAmountDiscount"] +__all__ = ["CouponCreateParams", "Discount", "DiscountNewCouponPercentageDiscount", "DiscountNewCouponAmountDiscount"] class CouponCreateParams(TypedDict, total=False): @@ -27,37 +27,16 @@ class CouponCreateParams(TypedDict, total=False): """ -class DiscountPercentageDiscount(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. - """ - +class DiscountNewCouponPercentageDiscount(TypedDict, total=False): 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 DiscountAmountDiscount(TypedDict, total=False): +class DiscountNewCouponAmountDiscount(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 = Union[DiscountPercentageDiscount, DiscountAmountDiscount] +Discount: TypeAlias = Union[DiscountNewCouponPercentageDiscount, DiscountNewCouponAmountDiscount] diff --git a/src/orb/types/credit_block_list_invoices_response.py b/src/orb/types/credit_block_list_invoices_response.py new file mode 100644 index 00000000..58cd20a6 --- /dev/null +++ b/src/orb/types/credit_block_list_invoices_response.py @@ -0,0 +1,127 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel +from .shared.custom_expiration import CustomExpiration +from .shared.customer_minified import CustomerMinified +from .shared.subscription_minified import SubscriptionMinified + +__all__ = [ + "CreditBlockListInvoicesResponse", + "Block", + "BlockFilter", + "BlockCreditAllocation", + "BlockCreditAllocationFilter", + "Invoice", +] + + +class BlockFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class BlockCreditAllocationFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class BlockCreditAllocation(BaseModel): + """The credit allocation that funded a block. + + Extends the allocation resource + serialized on prices with the catalog-item attribution of the funding price. + """ + + allows_rollover: bool + + currency: str + + custom_expiration: Optional[CustomExpiration] = None + + item_id: str + """ + The ID of the catalog item this block was allocated from, derived from the + allocation's price. + """ + + filters: Optional[List[BlockCreditAllocationFilter]] = None + + license_type_id: Optional[str] = None + + +class Block(BaseModel): + """The Credit Block resource models prepaid credits within Orb.""" + + id: str + + balance: float + + credit_block_source: Literal["allocation", "top_up", "manual"] + """ + How this credit block was created: `allocation` (a subscription's recurring + credit allocation), `top_up` (an automatic balance-threshold top-up), or + `manual` (a manual credit ledger increment, including credits voided or expired + off another block). + """ + + effective_date: Optional[datetime] = None + + expiry_date: Optional[datetime] = None + + filters: List[BlockFilter] + + maximum_initial_balance: Optional[float] = 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`. + """ + + per_unit_cost_basis: Optional[str] = None + + status: Literal["active", "pending_payment"] + + credit_allocation: Optional[BlockCreditAllocation] = None + """The credit allocation that funded a block. + + Extends the allocation resource serialized on prices with the catalog-item + attribution of the funding price. + """ + + +class Invoice(BaseModel): + id: str + + customer: CustomerMinified + + invoice_number: str + + status: Literal["issued", "paid", "synced", "void", "draft"] + + subscription: Optional[SubscriptionMinified] = None + + +class CreditBlockListInvoicesResponse(BaseModel): + block: Block + """The Credit Block resource models prepaid credits within Orb.""" + + invoices: List[Invoice] diff --git a/src/orb/types/credit_block_retrieve_response.py b/src/orb/types/credit_block_retrieve_response.py new file mode 100644 index 00000000..f7dc3d7d --- /dev/null +++ b/src/orb/types/credit_block_retrieve_response.py @@ -0,0 +1,99 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel +from .shared.custom_expiration import CustomExpiration + +__all__ = ["CreditBlockRetrieveResponse", "Filter", "CreditAllocation", "CreditAllocationFilter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class CreditAllocationFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class CreditAllocation(BaseModel): + """The credit allocation that funded a block. + + Extends the allocation resource + serialized on prices with the catalog-item attribution of the funding price. + """ + + allows_rollover: bool + + currency: str + + custom_expiration: Optional[CustomExpiration] = None + + item_id: str + """ + The ID of the catalog item this block was allocated from, derived from the + allocation's price. + """ + + filters: Optional[List[CreditAllocationFilter]] = None + + license_type_id: Optional[str] = None + + +class CreditBlockRetrieveResponse(BaseModel): + """The Credit Block resource models prepaid credits within Orb.""" + + id: str + + balance: float + + credit_block_source: Literal["allocation", "top_up", "manual"] + """ + How this credit block was created: `allocation` (a subscription's recurring + credit allocation), `top_up` (an automatic balance-threshold top-up), or + `manual` (a manual credit ledger increment, including credits voided or expired + off another block). + """ + + effective_date: Optional[datetime] = None + + expiry_date: Optional[datetime] = None + + filters: List[Filter] + + maximum_initial_balance: Optional[float] = 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`. + """ + + per_unit_cost_basis: Optional[str] = None + + status: Literal["active", "pending_payment"] + + credit_allocation: Optional[CreditAllocation] = None + """The credit allocation that funded a block. + + Extends the allocation resource serialized on prices with the catalog-item + attribution of the funding price. + """ 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..8e58bceb --- /dev/null +++ b/src/orb/types/credit_note_create_params.py @@ -0,0 +1,62 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from datetime import date +from typing_extensions import Literal, Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["CreditNoteCreateParams", "LineItem"] + + +class CreditNoteCreateParams(TypedDict, total=False): + line_items: Required[Iterable[LineItem]] + + reason: Required[Literal["duplicate", "fraudulent", "order_change", "product_unsatisfactory"]] + """An optional reason for the credit note.""" + + end_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """ + A date string to specify the global credit note service period end date in the + customer's timezone. This will be applied to all line items that don't have + their own individual service periods specified. If not provided, line items will + use their original invoice line item service periods. This date is inclusive. + """ + + memo: Optional[str] + """An optional memo to attach to the credit note.""" + + start_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """ + A date string to specify the global credit note service period start date in the + customer's timezone. This will be applied to all line items that don't have + their own individual service periods specified. If not provided, line items will + use their original invoice line item service periods. This date is inclusive. + """ + + +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.""" + + end_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """ + A date string to specify this line item's credit note service period end date in + the customer's timezone. If provided, this will be used for this specific line + item. If not provided, will use the global end_date if available, otherwise + defaults to the original invoice line item's end date. This date is inclusive. + """ + + start_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """ + A date string to specify this line item's credit note service period start date + in the customer's timezone. If provided, this will be used for this specific + line item. If not provided, will use the global start_date if available, + otherwise defaults to the original invoice line item's start date. This date is + inclusive. + """ diff --git a/src/orb/types/credit_note_list_params.py b/src/orb/types/credit_note_list_params.py index fa1314af..eeeccfc8 100644 --- a/src/orb/types/credit_note_list_params.py +++ b/src/orb/types/credit_note_list_params.py @@ -2,13 +2,24 @@ from __future__ import annotations -from typing import Optional -from typing_extensions import TypedDict +from typing import Union, Optional +from datetime import datetime +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo __all__ = ["CreditNoteListParams"] class CreditNoteListParams(TypedDict, total=False): + created_at_gt: Annotated[Union[str, datetime, None], PropertyInfo(alias="created_at[gt]", format="iso8601")] + + created_at_gte: Annotated[Union[str, datetime, None], PropertyInfo(alias="created_at[gte]", format="iso8601")] + + created_at_lt: Annotated[Union[str, datetime, None], PropertyInfo(alias="created_at[lt]", format="iso8601")] + + created_at_lte: Annotated[Union[str, datetime, None], PropertyInfo(alias="created_at[lte]", format="iso8601")] + cursor: Optional[str] """Cursor for pagination. diff --git a/src/orb/types/customer.py b/src/orb/types/customer.py index df9358dd..1c8ec876 100644 --- a/src/orb/types/customer.py +++ b/src/orb/types/customer.py @@ -5,167 +5,28 @@ from typing_extensions import Literal from .._models import BaseModel +from .shared.address import Address +from .shared.customer_tax_id import CustomerTaxID +from .shared.customer_minified import CustomerMinified __all__ = [ "Customer", - "BillingAddress", - "ShippingAddress", - "TaxID", + "Hierarchy", "AccountingSyncConfiguration", "AccountingSyncConfigurationAccountingProvider", + "DefaultPaymentMethod", + "PaymentConfiguration", + "PaymentConfigurationPaymentProvider", "ReportingConfiguration", ] -class BillingAddress(BaseModel): - city: Optional[str] = None - - country: Optional[str] = None - - line1: Optional[str] = None - - line2: Optional[str] = None - - postal_code: Optional[str] = None - - state: Optional[str] = None - - -class ShippingAddress(BaseModel): - city: Optional[str] = None - - country: Optional[str] = None - - line1: Optional[str] = None - - line2: Optional[str] = None - - postal_code: Optional[str] = None - - state: Optional[str] = None - - -class TaxID(BaseModel): - country: Literal[ - "AD", - "AE", - "AT", - "AU", - "BE", - "BG", - "BR", - "CA", - "CH", - "CL", - "CY", - "CZ", - "DE", - "DK", - "EE", - "EG", - "ES", - "EU", - "FI", - "FR", - "GB", - "GE", - "GR", - "HK", - "HR", - "HU", - "ID", - "IE", - "IL", - "IN", - "IS", - "IT", - "JP", - "KE", - "KR", - "LI", - "LT", - "LU", - "LV", - "MT", - "MX", - "MY", - "NL", - "NO", - "NZ", - "PH", - "PL", - "PT", - "RO", - "RU", - "SA", - "SE", - "SG", - "SI", - "SK", - "TH", - "TR", - "TW", - "UA", - "US", - "ZA", - ] - - type: Literal[ - "ad_nrt", - "ae_trn", - "eu_vat", - "au_abn", - "au_arn", - "bg_uic", - "br_cnpj", - "br_cpf", - "ca_bn", - "ca_gst_hst", - "ca_pst_bc", - "ca_pst_mb", - "ca_pst_sk", - "ca_qst", - "ch_vat", - "cl_tin", - "eg_tin", - "es_cif", - "eu_oss_vat", - "gb_vat", - "ge_vat", - "hk_br", - "hu_tin", - "id_npwp", - "il_vat", - "in_gst", - "is_vat", - "jp_cn", - "jp_rn", - "jp_trn", - "ke_pin", - "kr_brn", - "li_uid", - "mx_rfc", - "my_frp", - "my_itn", - "my_sst", - "no_vat", - "nz_gst", - "ph_tin", - "ru_inn", - "ru_kpp", - "sa_vat", - "sg_gst", - "sg_uen", - "si_tin", - "th_vat", - "tr_tin", - "tw_vat", - "ua_vat", - "us_ein", - "za_vat", - ] - - value: str +class Hierarchy(BaseModel): + """The hierarchical relationships for this customer.""" + + children: List[CustomerMinified] + + parent: Optional[CustomerMinified] = None class AccountingSyncConfigurationAccountingProvider(BaseModel): @@ -180,21 +41,113 @@ class AccountingSyncConfiguration(BaseModel): excluded: bool +class DefaultPaymentMethod(BaseModel): + """ + A payment method represents a customer's stored payment instrument held with an external payment + provider (such as Adyen or Stripe). + + The serialization is intentionally minimal for now; provider-pulled details (e.g. card display + metadata) will be added over time. + """ + + id: str + """The Orb-assigned unique identifier for the payment method.""" + + created_at: datetime + """The time at which the payment method was created.""" + + customer_id: str + """The ID of the Orb customer this payment method is attached to.""" + + default: bool + """Whether this is the customer's default payment method.""" + + external_payment_method_id: str + """The identifier of this payment method in the external payment provider.""" + + payment_method_type: Literal["card", "us_bank_account", "link", "amazon_pay", "crypto"] + """The type of the underlying payment instrument, e.g. + + `card` or `us_bank_account`. + """ + + provider_type: Optional[str] = None + """ + The external payment provider this method belongs to, derived from the linked + payment gateway connection (e.g. `adyen` or `stripe`). Null if the connection + has been removed. + """ + + +class PaymentConfigurationPaymentProvider(BaseModel): + provider_type: Literal["stripe"] + """The payment provider to configure.""" + + default_shared_payment_token: Optional[str] = None + """ + The ID of a shared payment token granted by an agent to use as the default + payment instrument for this customer. When set, auto-collection will use this + token instead of the customer's default payment method. + """ + + excluded_payment_method_types: Optional[List[str]] = None + """List of Stripe payment method types to exclude for this customer. + + Excluded payment methods will not be available for the customer to select during + payment, and will not be used for auto-collection. If a customer's default + payment method becomes excluded, Orb will attempt to use the next available + compatible payment method for auto-collection. + """ + + +class PaymentConfiguration(BaseModel): + """ + Payment configuration for the customer, applicable when using Orb Invoicing with a supported payment provider such as Stripe. + """ + + payment_providers: Optional[List[PaymentConfigurationPaymentProvider]] = None + """Provider-specific payment configuration.""" + + class ReportingConfiguration(BaseModel): exempt: bool class Customer(BaseModel): + """ + 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](/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](/essentials/timezones) for + information on what this timezone parameter influences within Orb. + """ + id: str additional_emails: List[str] auto_collection: bool + auto_issuance: Optional[bool] = None + """Whether invoices for this customer should be automatically issued. + + If true, invoices will be automatically issued. If false, invoices will require + manual approval. If null, inherits the account-level setting. + """ + balance: str """The customer's current balance in their currency.""" - billing_address: Optional[BillingAddress] = None + billing_address: Optional[Address] = None created_at: datetime @@ -209,6 +162,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 @@ -216,6 +171,9 @@ class Customer(BaseModel): an existing identifier in your system. """ + hierarchy: Hierarchy + """The hierarchical relationships for this customer.""" + metadata: Dict[str, str] """User specified key-value pairs for the resource. @@ -227,7 +185,9 @@ class Customer(BaseModel): name: str """The full name of the customer""" - payment_provider: Optional[Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite"]] = None + payment_provider: Optional[ + Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite", "adyen"] + ] = None """This is used for creating charges or invoices in an external system via Orb. When not in test mode, the connection must first be configured in the Orb @@ -241,96 +201,168 @@ class Customer(BaseModel): """ portal_url: Optional[str] = None + """Deprecated. + + Returns the URL of the most recent non-expired portal link, or null. When the + account has opted into customer portal sessions, this field always returns null. + Use POST /v1/customers/{id}/portal_sessions to mint short-lived portal session + URLs. + """ - shipping_address: Optional[ShippingAddress] = None + shipping_address: Optional[Address] = None - tax_id: Optional[TaxID] = None + tax_id: Optional[CustomerTaxID] = None """ Tax IDs are commonly required to be displayed on customer invoices, which are added to the headers of invoices. ### Supported Tax ID Countries and Types - | Country | Type | Description | - | -------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | - | Andorra | `ad_nrt` | Andorran NRT number | - | Australia | `au_abn` | Australian Business Number (AU ABN) | - | Australia | `au_arn` | Australian Taxation Office Reference Number | - | Austria | `eu_vat` | European VAT number | - | Belgium | `eu_vat` | European VAT number | - | Brazil | `br_cnpj` | Brazilian CNPJ number | - | Brazil | `br_cpf` | Brazilian CPF number | - | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | - | Bulgaria | `eu_vat` | European VAT number | - | Canada | `ca_bn` | Canadian BN | - | Canada | `ca_gst_hst` | Canadian GST/HST number | - | Canada | `ca_pst_bc` | Canadian PST number (British Columbia) | - | Canada | `ca_pst_mb` | Canadian PST number (Manitoba) | - | Canada | `ca_pst_sk` | Canadian PST number (Saskatchewan) | - | Canada | `ca_qst` | Canadian QST number (Québec) | - | Chile | `cl_tin` | Chilean TIN | - | Croatia | `eu_vat` | European VAT number | - | Cyprus | `eu_vat` | European VAT number | - | Czech Republic | `eu_vat` | European VAT number | - | Denmark | `eu_vat` | European VAT number | - | Egypt | `eg_tin` | Egyptian Tax Identification Number | - | Estonia | `eu_vat` | European VAT number | - | EU | `eu_oss_vat` | European One Stop Shop VAT number for non-Union scheme | - | Finland | `eu_vat` | European VAT number | - | France | `eu_vat` | European VAT number | - | Georgia | `ge_vat` | Georgian VAT | - | Germany | `eu_vat` | European VAT number | - | Greece | `eu_vat` | European VAT number | - | Hong Kong | `hk_br` | Hong Kong BR number | - | Hungary | `eu_vat` | European VAT number | - | Hungary | `hu_tin` | Hungary tax number (adószám) | - | Iceland | `is_vat` | Icelandic VAT | - | India | `in_gst` | Indian GST number | - | Indonesia | `id_npwp` | Indonesian NPWP number | - | Ireland | `eu_vat` | European VAT number | - | Israel | `il_vat` | Israel VAT | - | Italy | `eu_vat` | European VAT number | - | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | - | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | - | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | - | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | - | Latvia | `eu_vat` | European VAT number | - | Liechtenstein | `li_uid` | Liechtensteinian UID number | - | Lithuania | `eu_vat` | European VAT number | - | Luxembourg | `eu_vat` | European VAT number | - | Malaysia | `my_frp` | Malaysian FRP number | - | Malaysia | `my_itn` | Malaysian ITN | - | Malaysia | `my_sst` | Malaysian SST number | - | Malta | `eu_vat ` | European VAT number | - | Mexico | `mx_rfc` | Mexican RFC number | - | Netherlands | `eu_vat` | European VAT number | - | New Zealand | `nz_gst` | New Zealand GST number | - | Norway | `no_vat` | Norwegian VAT number | - | Philippines | `ph_tin ` | Philippines Tax Identification Number | - | Poland | `eu_vat` | European VAT number | - | Portugal | `eu_vat` | European VAT number | - | Romania | `eu_vat` | European VAT number | - | Russia | `ru_inn` | Russian INN | - | Russia | `ru_kpp` | Russian KPP | - | Saudi Arabia | `sg_gst` | Singaporean GST | - | Singapore | `sg_uen` | Singaporean UEN | - | Slovakia | `eu_vat` | European VAT number | - | Slovenia | `eu_vat` | European VAT number | - | Slovenia | `si_tin` | Slovenia tax number (davčna številka) | - | South Africa | `za_vat` | South African VAT number | - | South Korea | `kr_brn` | Korean BRN | - | Spain | `es_cif` | Spanish NIF number (previously Spanish CIF number) | - | Spain | `eu_vat` | European VAT number | - | Sweden | `eu_vat` | European VAT number | - | Switzerland | `ch_vat` | Switzerland VAT number | - | Taiwan | `tw_vat` | Taiwanese VAT | - | Thailand | `th_vat` | Thai VAT | - | Turkey | `tr_tin` | Turkish Tax Identification Number | - | Ukraine | `ua_vat` | Ukrainian VAT | - | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | - | United Kingdom | `eu_vat` | Northern Ireland VAT number | - | United Kingdom | `gb_vat` | United Kingdom VAT number | - | United States | `us_ein` | United States EIN | + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | """ timezone: str @@ -342,4 +374,26 @@ class Customer(BaseModel): accounting_sync_configuration: Optional[AccountingSyncConfiguration] = None + automatic_tax_enabled: Optional[bool] = None + """Whether automatic tax calculation is enabled for this customer. + + This field is nullable for backwards compatibility but will always return a + boolean value. + """ + + default_payment_method: Optional[DefaultPaymentMethod] = None + """ + A payment method represents a customer's stored payment instrument held with an + external payment provider (such as Adyen or Stripe). + + The serialization is intentionally minimal for now; provider-pulled details + (e.g. card display metadata) will be added over time. + """ + + payment_configuration: Optional[PaymentConfiguration] = None + """ + Payment configuration for the customer, applicable when using Orb Invoicing with + a supported payment provider such as Stripe. + """ + reporting_configuration: Optional[ReportingConfiguration] = None diff --git a/src/orb/types/customer_create_params.py b/src/orb/types/customer_create_params.py index 9e08fb6c..30fcff70 100644 --- a/src/orb/types/customer_create_params.py +++ b/src/orb/types/customer_create_params.py @@ -2,17 +2,27 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .address_input_param import AddressInputParam +from .shared_params.customer_tax_id import CustomerTaxID +from .new_sphere_configuration_param import NewSphereConfigurationParam +from .customer_hierarchy_config_param import CustomerHierarchyConfigParam +from .new_tax_jar_configuration_param import NewTaxJarConfigurationParam +from .new_reporting_configuration_param import NewReportingConfigurationParam +from .new_avalara_tax_configuration_param import NewAvalaraTaxConfigurationParam +from .new_accounting_sync_configuration_param import NewAccountingSyncConfigurationParam __all__ = [ "CustomerCreateParams", - "AccountingSyncConfiguration", - "AccountingSyncConfigurationAccountingProvider", - "BillingAddress", - "ReportingConfiguration", - "ShippingAddress", - "TaxID", + "PaymentConfiguration", + "PaymentConfigurationPaymentProvider", + "TaxConfiguration", + "TaxConfigurationNewNumeralConfiguration", + "TaxConfigurationNewAnrokConfiguration", + "TaxConfigurationNewStripeTaxConfiguration", ] @@ -27,12 +37,14 @@ class CustomerCreateParams(TypedDict, total=False): name: Required[str] """The full name of the customer""" - accounting_sync_configuration: Optional[AccountingSyncConfiguration] + accounting_sync_configuration: Optional[NewAccountingSyncConfigurationParam] - additional_emails: Optional[List[str]] + additional_emails: Optional[SequenceNotStr[str]] """Additional email addresses for this customer. If populated, these email addresses will be CC'd for customer communications. + The total number of email addresses (including the primary email) cannot + exceed 50. """ auto_collection: Optional[bool] @@ -42,7 +54,15 @@ class CustomerCreateParams(TypedDict, total=False): when a payment provider is provided on customer creation. """ - billing_address: Optional[BillingAddress] + auto_issuance: Optional[bool] + """Used to determine if invoices for this customer will be automatically issued. + + If true, invoices will be automatically issued. If false, invoices will require + manual approval. If `null` is specified, the customer's auto issuance setting + will be inherited from the account-level setting. + """ + + billing_address: Optional[AddressInputParam] currency: Optional[str] """An ISO 4217 currency string used for the customer's invoices and balance. @@ -59,6 +79,9 @@ class CustomerCreateParams(TypedDict, total=False): an existing identifier in your system. """ + hierarchy: Optional[CustomerHierarchyConfigParam] + """The hierarchical relationships for this customer.""" + metadata: Optional[Dict[str, Optional[str]]] """User-specified key/value pairs for the resource. @@ -66,7 +89,15 @@ class CustomerCreateParams(TypedDict, total=False): metadata mapping can be cleared by setting `metadata` to `null`. """ - payment_provider: Optional[Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite"]] + payment_configuration: Optional[PaymentConfiguration] + """ + Payment configuration for the customer, applicable when using Orb Invoicing with + a supported payment provider such as Stripe. + """ + + payment_provider: Optional[ + Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite", "adyen"] + ] """This is used for creating charges or invoices in an external system via Orb. When not in test mode, the connection must first be configured in the Orb @@ -79,97 +110,164 @@ class CustomerCreateParams(TypedDict, total=False): This is used for creating charges or invoices in the external system via Orb. """ - reporting_configuration: Optional[ReportingConfiguration] + reporting_configuration: Optional[NewReportingConfigurationParam] + + shipping_address: Optional[AddressInputParam] - shipping_address: Optional[ShippingAddress] + tax_configuration: Optional[TaxConfiguration] - tax_id: Optional[TaxID] + tax_id: Optional[CustomerTaxID] """ Tax IDs are commonly required to be displayed on customer invoices, which are added to the headers of invoices. ### Supported Tax ID Countries and Types - | Country | Type | Description | - | -------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | - | Andorra | `ad_nrt` | Andorran NRT number | - | Australia | `au_abn` | Australian Business Number (AU ABN) | - | Australia | `au_arn` | Australian Taxation Office Reference Number | - | Austria | `eu_vat` | European VAT number | - | Belgium | `eu_vat` | European VAT number | - | Brazil | `br_cnpj` | Brazilian CNPJ number | - | Brazil | `br_cpf` | Brazilian CPF number | - | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | - | Bulgaria | `eu_vat` | European VAT number | - | Canada | `ca_bn` | Canadian BN | - | Canada | `ca_gst_hst` | Canadian GST/HST number | - | Canada | `ca_pst_bc` | Canadian PST number (British Columbia) | - | Canada | `ca_pst_mb` | Canadian PST number (Manitoba) | - | Canada | `ca_pst_sk` | Canadian PST number (Saskatchewan) | - | Canada | `ca_qst` | Canadian QST number (Québec) | - | Chile | `cl_tin` | Chilean TIN | - | Croatia | `eu_vat` | European VAT number | - | Cyprus | `eu_vat` | European VAT number | - | Czech Republic | `eu_vat` | European VAT number | - | Denmark | `eu_vat` | European VAT number | - | Egypt | `eg_tin` | Egyptian Tax Identification Number | - | Estonia | `eu_vat` | European VAT number | - | EU | `eu_oss_vat` | European One Stop Shop VAT number for non-Union scheme | - | Finland | `eu_vat` | European VAT number | - | France | `eu_vat` | European VAT number | - | Georgia | `ge_vat` | Georgian VAT | - | Germany | `eu_vat` | European VAT number | - | Greece | `eu_vat` | European VAT number | - | Hong Kong | `hk_br` | Hong Kong BR number | - | Hungary | `eu_vat` | European VAT number | - | Hungary | `hu_tin` | Hungary tax number (adószám) | - | Iceland | `is_vat` | Icelandic VAT | - | India | `in_gst` | Indian GST number | - | Indonesia | `id_npwp` | Indonesian NPWP number | - | Ireland | `eu_vat` | European VAT number | - | Israel | `il_vat` | Israel VAT | - | Italy | `eu_vat` | European VAT number | - | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | - | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | - | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | - | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | - | Latvia | `eu_vat` | European VAT number | - | Liechtenstein | `li_uid` | Liechtensteinian UID number | - | Lithuania | `eu_vat` | European VAT number | - | Luxembourg | `eu_vat` | European VAT number | - | Malaysia | `my_frp` | Malaysian FRP number | - | Malaysia | `my_itn` | Malaysian ITN | - | Malaysia | `my_sst` | Malaysian SST number | - | Malta | `eu_vat ` | European VAT number | - | Mexico | `mx_rfc` | Mexican RFC number | - | Netherlands | `eu_vat` | European VAT number | - | New Zealand | `nz_gst` | New Zealand GST number | - | Norway | `no_vat` | Norwegian VAT number | - | Philippines | `ph_tin ` | Philippines Tax Identification Number | - | Poland | `eu_vat` | European VAT number | - | Portugal | `eu_vat` | European VAT number | - | Romania | `eu_vat` | European VAT number | - | Russia | `ru_inn` | Russian INN | - | Russia | `ru_kpp` | Russian KPP | - | Saudi Arabia | `sg_gst` | Singaporean GST | - | Singapore | `sg_uen` | Singaporean UEN | - | Slovakia | `eu_vat` | European VAT number | - | Slovenia | `eu_vat` | European VAT number | - | Slovenia | `si_tin` | Slovenia tax number (davčna številka) | - | South Africa | `za_vat` | South African VAT number | - | South Korea | `kr_brn` | Korean BRN | - | Spain | `es_cif` | Spanish NIF number (previously Spanish CIF number) | - | Spain | `eu_vat` | European VAT number | - | Sweden | `eu_vat` | European VAT number | - | Switzerland | `ch_vat` | Switzerland VAT number | - | Taiwan | `tw_vat` | Taiwanese VAT | - | Thailand | `th_vat` | Thai VAT | - | Turkey | `tr_tin` | Turkish Tax Identification Number | - | Ukraine | `ua_vat` | Ukrainian VAT | - | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | - | United Kingdom | `eu_vat` | Northern Ireland VAT number | - | United Kingdom | `gb_vat` | United Kingdom VAT number | - | United States | `us_ein` | United States EIN | + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | """ timezone: Optional[str] @@ -180,172 +278,80 @@ class CustomerCreateParams(TypedDict, total=False): """ -class AccountingSyncConfigurationAccountingProvider(TypedDict, total=False): - external_provider_id: Required[str] - - provider_type: Required[str] - - -class AccountingSyncConfiguration(TypedDict, total=False): - accounting_providers: Optional[Iterable[AccountingSyncConfigurationAccountingProvider]] - - excluded: Optional[bool] - - -class BillingAddress(TypedDict, total=False): - city: Optional[str] - - country: Optional[str] - - line1: Optional[str] - - line2: Optional[str] - - postal_code: Optional[str] - - state: Optional[str] - - -class ReportingConfiguration(TypedDict, total=False): - exempt: Required[bool] - - -class ShippingAddress(TypedDict, total=False): - city: Optional[str] - - country: Optional[str] - - line1: Optional[str] - - line2: Optional[str] - - postal_code: Optional[str] - - state: Optional[str] - - -class TaxID(TypedDict, total=False): - country: Required[ - Literal[ - "AD", - "AE", - "AT", - "AU", - "BE", - "BG", - "BR", - "CA", - "CH", - "CL", - "CY", - "CZ", - "DE", - "DK", - "EE", - "EG", - "ES", - "EU", - "FI", - "FR", - "GB", - "GE", - "GR", - "HK", - "HR", - "HU", - "ID", - "IE", - "IL", - "IN", - "IS", - "IT", - "JP", - "KE", - "KR", - "LI", - "LT", - "LU", - "LV", - "MT", - "MX", - "MY", - "NL", - "NO", - "NZ", - "PH", - "PL", - "PT", - "RO", - "RU", - "SA", - "SE", - "SG", - "SI", - "SK", - "TH", - "TR", - "TW", - "UA", - "US", - "ZA", - ] - ] +class PaymentConfigurationPaymentProvider(TypedDict, total=False): + provider_type: Required[Literal["stripe"]] + """The payment provider to configure.""" - type: Required[ - Literal[ - "ad_nrt", - "ae_trn", - "eu_vat", - "au_abn", - "au_arn", - "bg_uic", - "br_cnpj", - "br_cpf", - "ca_bn", - "ca_gst_hst", - "ca_pst_bc", - "ca_pst_mb", - "ca_pst_sk", - "ca_qst", - "ch_vat", - "cl_tin", - "eg_tin", - "es_cif", - "eu_oss_vat", - "gb_vat", - "ge_vat", - "hk_br", - "hu_tin", - "id_npwp", - "il_vat", - "in_gst", - "is_vat", - "jp_cn", - "jp_rn", - "jp_trn", - "ke_pin", - "kr_brn", - "li_uid", - "mx_rfc", - "my_frp", - "my_itn", - "my_sst", - "no_vat", - "nz_gst", - "ph_tin", - "ru_inn", - "ru_kpp", - "sa_vat", - "sg_gst", - "sg_uen", - "si_tin", - "th_vat", - "tr_tin", - "tw_vat", - "ua_vat", - "us_ein", - "za_vat", - ] - ] + default_shared_payment_token: Optional[str] + """ + The ID of a shared payment token granted by an agent to use as the default + payment instrument for this customer. When set, auto-collection will use this + token instead of the customer's default payment method. + """ + + excluded_payment_method_types: SequenceNotStr[str] + """List of Stripe payment method types to exclude for this customer. + + Excluded payment methods will not be available for the customer to select during + payment, and will not be used for auto-collection. If a customer's default + payment method becomes excluded, Orb will attempt to use the next available + compatible payment method for auto-collection. + """ + + +class PaymentConfiguration(TypedDict, total=False): + """ + Payment configuration for the customer, applicable when using Orb Invoicing with a supported payment provider such as Stripe. + """ + + payment_providers: Iterable[PaymentConfigurationPaymentProvider] + """Provider-specific payment configuration.""" - value: Required[str] + +class TaxConfigurationNewNumeralConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["numeral"]] + + automatic_tax_enabled: Optional[bool] + """Whether to automatically calculate tax for this customer. + + When null, inherits from account-level setting. When true or false, overrides + the account setting. + """ + + +class TaxConfigurationNewAnrokConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["anrok"]] + + automatic_tax_enabled: Optional[bool] + """Whether to automatically calculate tax for this customer. + + When null, inherits from account-level setting. When true or false, overrides + the account setting. + """ + + +class TaxConfigurationNewStripeTaxConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["stripe"]] + + automatic_tax_enabled: Optional[bool] + """Whether to automatically calculate tax for this customer. + + When null, inherits from account-level setting. When true or false, overrides + the account setting. + """ + + +TaxConfiguration: TypeAlias = Union[ + NewAvalaraTaxConfigurationParam, + NewTaxJarConfigurationParam, + NewSphereConfigurationParam, + TaxConfigurationNewNumeralConfiguration, + TaxConfigurationNewAnrokConfiguration, + TaxConfigurationNewStripeTaxConfiguration, +] diff --git a/src/orb/types/customer_hierarchy_config_param.py b/src/orb/types/customer_hierarchy_config_param.py new file mode 100644 index 00000000..a89c124e --- /dev/null +++ b/src/orb/types/customer_hierarchy_config_param.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +from .._types import SequenceNotStr + +__all__ = ["CustomerHierarchyConfigParam"] + + +class CustomerHierarchyConfigParam(TypedDict, total=False): + child_customer_ids: SequenceNotStr[str] + """A list of child customer IDs to add to the hierarchy. + + The desired child customers must not already be part of another hierarchy. + """ + + parent_customer_id: Optional[str] + """The ID of the parent customer in the hierarchy. + + The desired parent customer must not be a child of another customer. + """ 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 6c12f279..e82c9cf5 100644 --- a/src/orb/types/customer_update_by_external_id_params.py +++ b/src/orb/types/customer_update_by_external_id_params.py @@ -2,27 +2,39 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .address_input_param import AddressInputParam +from .shared_params.customer_tax_id import CustomerTaxID +from .new_sphere_configuration_param import NewSphereConfigurationParam +from .customer_hierarchy_config_param import CustomerHierarchyConfigParam +from .new_tax_jar_configuration_param import NewTaxJarConfigurationParam +from .new_reporting_configuration_param import NewReportingConfigurationParam +from .new_avalara_tax_configuration_param import NewAvalaraTaxConfigurationParam +from .new_accounting_sync_configuration_param import NewAccountingSyncConfigurationParam __all__ = [ "CustomerUpdateByExternalIDParams", - "AccountingSyncConfiguration", - "AccountingSyncConfigurationAccountingProvider", - "BillingAddress", - "ReportingConfiguration", - "ShippingAddress", - "TaxID", + "PaymentConfiguration", + "PaymentConfigurationPaymentProvider", + "TaxConfiguration", + "TaxConfigurationNewNumeralConfiguration", + "TaxConfigurationNewAnrokConfiguration", + "TaxConfigurationNewStripeTaxConfiguration", ] class CustomerUpdateByExternalIDParams(TypedDict, total=False): - accounting_sync_configuration: Optional[AccountingSyncConfiguration] + accounting_sync_configuration: Optional[NewAccountingSyncConfigurationParam] - additional_emails: Optional[List[str]] + additional_emails: Optional[SequenceNotStr[str]] """Additional email addresses for this customer. If populated, these email addresses will be CC'd for customer communications. + The total number of email addresses (including the primary email) cannot + exceed 50. """ auto_collection: Optional[bool] @@ -32,12 +44,28 @@ class CustomerUpdateByExternalIDParams(TypedDict, total=False): when a payment provider is provided on customer creation. """ - billing_address: Optional[BillingAddress] + auto_issuance: Optional[bool] + """Used to determine if invoices for this customer will be automatically issued. + + If true, invoices will be automatically issued. If false, invoices will require + manual approval.If `null` is specified, the customer's auto issuance setting + will be inherited from the account-level setting. + """ + + billing_address: Optional[AddressInputParam] currency: Optional[str] """An ISO 4217 currency string used for the customer's invoices and balance. - If not set at creation time, will be set at subscription creation time. + This can only be set if the customer does not already have a currency + configured. If not set at creation or update time, it will be set at + subscription creation time. + """ + + default_payment_method_id: Optional[str] + """The Orb ID of the payment method to set as this customer's default. + + Pass `null` to clear the customer's default payment method. """ email: Optional[str] @@ -48,10 +76,15 @@ class CustomerUpdateByExternalIDParams(TypedDict, total=False): external_customer_id: Optional[str] """The external customer ID. - This can only be set if empty and the customer has no past or current - subscriptions. + This can only be set if the customer has no existing external customer ID. Since + this action may change usage quantities for all existing subscriptions, it is + disallowed if the customer has issued invoices with usage line items and subject + to the same restrictions as backdated subscription creation. """ + hierarchy: Optional[CustomerHierarchyConfigParam] + """The hierarchical relationships for this customer.""" + metadata: Optional[Dict[str, Optional[str]]] """User-specified key/value pairs for the resource. @@ -62,7 +95,15 @@ class CustomerUpdateByExternalIDParams(TypedDict, total=False): name: Optional[str] """The full name of the customer""" - payment_provider: Optional[Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite"]] + payment_configuration: Optional[PaymentConfiguration] + """ + Payment configuration for the customer, applicable when using Orb Invoicing with + a supported payment provider such as Stripe. + """ + + payment_provider: Optional[ + Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite", "adyen"] + ] """This is used for creating charges or invoices in an external system via Orb. When not in test mode: @@ -79,266 +120,241 @@ class CustomerUpdateByExternalIDParams(TypedDict, total=False): This is used for creating charges or invoices in the external system via Orb. """ - reporting_configuration: Optional[ReportingConfiguration] + reporting_configuration: Optional[NewReportingConfigurationParam] - shipping_address: Optional[ShippingAddress] + shipping_address: Optional[AddressInputParam] - tax_id: Optional[TaxID] + tax_configuration: Optional[TaxConfiguration] + + tax_id: Optional[CustomerTaxID] """ Tax IDs are commonly required to be displayed on customer invoices, which are added to the headers of invoices. ### Supported Tax ID Countries and Types - | Country | Type | Description | - | -------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | - | Andorra | `ad_nrt` | Andorran NRT number | - | Australia | `au_abn` | Australian Business Number (AU ABN) | - | Australia | `au_arn` | Australian Taxation Office Reference Number | - | Austria | `eu_vat` | European VAT number | - | Belgium | `eu_vat` | European VAT number | - | Brazil | `br_cnpj` | Brazilian CNPJ number | - | Brazil | `br_cpf` | Brazilian CPF number | - | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | - | Bulgaria | `eu_vat` | European VAT number | - | Canada | `ca_bn` | Canadian BN | - | Canada | `ca_gst_hst` | Canadian GST/HST number | - | Canada | `ca_pst_bc` | Canadian PST number (British Columbia) | - | Canada | `ca_pst_mb` | Canadian PST number (Manitoba) | - | Canada | `ca_pst_sk` | Canadian PST number (Saskatchewan) | - | Canada | `ca_qst` | Canadian QST number (Québec) | - | Chile | `cl_tin` | Chilean TIN | - | Croatia | `eu_vat` | European VAT number | - | Cyprus | `eu_vat` | European VAT number | - | Czech Republic | `eu_vat` | European VAT number | - | Denmark | `eu_vat` | European VAT number | - | Egypt | `eg_tin` | Egyptian Tax Identification Number | - | Estonia | `eu_vat` | European VAT number | - | EU | `eu_oss_vat` | European One Stop Shop VAT number for non-Union scheme | - | Finland | `eu_vat` | European VAT number | - | France | `eu_vat` | European VAT number | - | Georgia | `ge_vat` | Georgian VAT | - | Germany | `eu_vat` | European VAT number | - | Greece | `eu_vat` | European VAT number | - | Hong Kong | `hk_br` | Hong Kong BR number | - | Hungary | `eu_vat` | European VAT number | - | Hungary | `hu_tin` | Hungary tax number (adószám) | - | Iceland | `is_vat` | Icelandic VAT | - | India | `in_gst` | Indian GST number | - | Indonesia | `id_npwp` | Indonesian NPWP number | - | Ireland | `eu_vat` | European VAT number | - | Israel | `il_vat` | Israel VAT | - | Italy | `eu_vat` | European VAT number | - | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | - | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | - | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | - | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | - | Latvia | `eu_vat` | European VAT number | - | Liechtenstein | `li_uid` | Liechtensteinian UID number | - | Lithuania | `eu_vat` | European VAT number | - | Luxembourg | `eu_vat` | European VAT number | - | Malaysia | `my_frp` | Malaysian FRP number | - | Malaysia | `my_itn` | Malaysian ITN | - | Malaysia | `my_sst` | Malaysian SST number | - | Malta | `eu_vat ` | European VAT number | - | Mexico | `mx_rfc` | Mexican RFC number | - | Netherlands | `eu_vat` | European VAT number | - | New Zealand | `nz_gst` | New Zealand GST number | - | Norway | `no_vat` | Norwegian VAT number | - | Philippines | `ph_tin ` | Philippines Tax Identification Number | - | Poland | `eu_vat` | European VAT number | - | Portugal | `eu_vat` | European VAT number | - | Romania | `eu_vat` | European VAT number | - | Russia | `ru_inn` | Russian INN | - | Russia | `ru_kpp` | Russian KPP | - | Saudi Arabia | `sg_gst` | Singaporean GST | - | Singapore | `sg_uen` | Singaporean UEN | - | Slovakia | `eu_vat` | European VAT number | - | Slovenia | `eu_vat` | European VAT number | - | Slovenia | `si_tin` | Slovenia tax number (davčna številka) | - | South Africa | `za_vat` | South African VAT number | - | South Korea | `kr_brn` | Korean BRN | - | Spain | `es_cif` | Spanish NIF number (previously Spanish CIF number) | - | Spain | `eu_vat` | European VAT number | - | Sweden | `eu_vat` | European VAT number | - | Switzerland | `ch_vat` | Switzerland VAT number | - | Taiwan | `tw_vat` | Taiwanese VAT | - | Thailand | `th_vat` | Thai VAT | - | Turkey | `tr_tin` | Turkish Tax Identification Number | - | Ukraine | `ua_vat` | Ukrainian VAT | - | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | - | United Kingdom | `eu_vat` | Northern Ireland VAT number | - | United Kingdom | `gb_vat` | United Kingdom VAT number | - | United States | `us_ein` | United States EIN | + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | """ -class AccountingSyncConfigurationAccountingProvider(TypedDict, total=False): - external_provider_id: Required[str] - - provider_type: Required[str] - - -class AccountingSyncConfiguration(TypedDict, total=False): - accounting_providers: Optional[Iterable[AccountingSyncConfigurationAccountingProvider]] - - excluded: Optional[bool] - - -class BillingAddress(TypedDict, total=False): - city: Optional[str] - - country: Optional[str] - - line1: Optional[str] - - line2: Optional[str] - - postal_code: Optional[str] - - state: Optional[str] - - -class ReportingConfiguration(TypedDict, total=False): - exempt: Required[bool] - - -class ShippingAddress(TypedDict, total=False): - city: Optional[str] - - country: Optional[str] - - line1: Optional[str] - - line2: Optional[str] - - postal_code: Optional[str] - - state: Optional[str] - - -class TaxID(TypedDict, total=False): - country: Required[ - Literal[ - "AD", - "AE", - "AT", - "AU", - "BE", - "BG", - "BR", - "CA", - "CH", - "CL", - "CY", - "CZ", - "DE", - "DK", - "EE", - "EG", - "ES", - "EU", - "FI", - "FR", - "GB", - "GE", - "GR", - "HK", - "HR", - "HU", - "ID", - "IE", - "IL", - "IN", - "IS", - "IT", - "JP", - "KE", - "KR", - "LI", - "LT", - "LU", - "LV", - "MT", - "MX", - "MY", - "NL", - "NO", - "NZ", - "PH", - "PL", - "PT", - "RO", - "RU", - "SA", - "SE", - "SG", - "SI", - "SK", - "TH", - "TR", - "TW", - "UA", - "US", - "ZA", - ] - ] +class PaymentConfigurationPaymentProvider(TypedDict, total=False): + provider_type: Required[Literal["stripe"]] + """The payment provider to configure.""" - type: Required[ - Literal[ - "ad_nrt", - "ae_trn", - "eu_vat", - "au_abn", - "au_arn", - "bg_uic", - "br_cnpj", - "br_cpf", - "ca_bn", - "ca_gst_hst", - "ca_pst_bc", - "ca_pst_mb", - "ca_pst_sk", - "ca_qst", - "ch_vat", - "cl_tin", - "eg_tin", - "es_cif", - "eu_oss_vat", - "gb_vat", - "ge_vat", - "hk_br", - "hu_tin", - "id_npwp", - "il_vat", - "in_gst", - "is_vat", - "jp_cn", - "jp_rn", - "jp_trn", - "ke_pin", - "kr_brn", - "li_uid", - "mx_rfc", - "my_frp", - "my_itn", - "my_sst", - "no_vat", - "nz_gst", - "ph_tin", - "ru_inn", - "ru_kpp", - "sa_vat", - "sg_gst", - "sg_uen", - "si_tin", - "th_vat", - "tr_tin", - "tw_vat", - "ua_vat", - "us_ein", - "za_vat", - ] - ] + default_shared_payment_token: Optional[str] + """ + The ID of a shared payment token granted by an agent to use as the default + payment instrument for this customer. When set, auto-collection will use this + token instead of the customer's default payment method. + """ + + excluded_payment_method_types: SequenceNotStr[str] + """List of Stripe payment method types to exclude for this customer. + + Excluded payment methods will not be available for the customer to select during + payment, and will not be used for auto-collection. If a customer's default + payment method becomes excluded, Orb will attempt to use the next available + compatible payment method for auto-collection. + """ + + +class PaymentConfiguration(TypedDict, total=False): + """ + Payment configuration for the customer, applicable when using Orb Invoicing with a supported payment provider such as Stripe. + """ + + payment_providers: Iterable[PaymentConfigurationPaymentProvider] + """Provider-specific payment configuration.""" + + +class TaxConfigurationNewNumeralConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["numeral"]] + + automatic_tax_enabled: Optional[bool] + """Whether to automatically calculate tax for this customer. + + When null, inherits from account-level setting. When true or false, overrides + the account setting. + """ + + +class TaxConfigurationNewAnrokConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["anrok"]] - value: Required[str] + automatic_tax_enabled: Optional[bool] + """Whether to automatically calculate tax for this customer. + + When null, inherits from account-level setting. When true or false, overrides + the account setting. + """ + + +class TaxConfigurationNewStripeTaxConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["stripe"]] + + automatic_tax_enabled: Optional[bool] + """Whether to automatically calculate tax for this customer. + + When null, inherits from account-level setting. When true or false, overrides + the account setting. + """ + + +TaxConfiguration: TypeAlias = Union[ + NewAvalaraTaxConfigurationParam, + NewTaxJarConfigurationParam, + NewSphereConfigurationParam, + TaxConfigurationNewNumeralConfiguration, + TaxConfigurationNewAnrokConfiguration, + TaxConfigurationNewStripeTaxConfiguration, +] diff --git a/src/orb/types/customer_update_params.py b/src/orb/types/customer_update_params.py index 66317375..1afa008d 100644 --- a/src/orb/types/customer_update_params.py +++ b/src/orb/types/customer_update_params.py @@ -2,27 +2,39 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .address_input_param import AddressInputParam +from .shared_params.customer_tax_id import CustomerTaxID +from .new_sphere_configuration_param import NewSphereConfigurationParam +from .customer_hierarchy_config_param import CustomerHierarchyConfigParam +from .new_tax_jar_configuration_param import NewTaxJarConfigurationParam +from .new_reporting_configuration_param import NewReportingConfigurationParam +from .new_avalara_tax_configuration_param import NewAvalaraTaxConfigurationParam +from .new_accounting_sync_configuration_param import NewAccountingSyncConfigurationParam __all__ = [ "CustomerUpdateParams", - "AccountingSyncConfiguration", - "AccountingSyncConfigurationAccountingProvider", - "BillingAddress", - "ReportingConfiguration", - "ShippingAddress", - "TaxID", + "PaymentConfiguration", + "PaymentConfigurationPaymentProvider", + "TaxConfiguration", + "TaxConfigurationNewNumeralConfiguration", + "TaxConfigurationNewAnrokConfiguration", + "TaxConfigurationNewStripeTaxConfiguration", ] class CustomerUpdateParams(TypedDict, total=False): - accounting_sync_configuration: Optional[AccountingSyncConfiguration] + accounting_sync_configuration: Optional[NewAccountingSyncConfigurationParam] - additional_emails: Optional[List[str]] + additional_emails: Optional[SequenceNotStr[str]] """Additional email addresses for this customer. If populated, these email addresses will be CC'd for customer communications. + The total number of email addresses (including the primary email) cannot + exceed 50. """ auto_collection: Optional[bool] @@ -32,12 +44,28 @@ class CustomerUpdateParams(TypedDict, total=False): when a payment provider is provided on customer creation. """ - billing_address: Optional[BillingAddress] + auto_issuance: Optional[bool] + """Used to determine if invoices for this customer will be automatically issued. + + If true, invoices will be automatically issued. If false, invoices will require + manual approval.If `null` is specified, the customer's auto issuance setting + will be inherited from the account-level setting. + """ + + billing_address: Optional[AddressInputParam] currency: Optional[str] """An ISO 4217 currency string used for the customer's invoices and balance. - If not set at creation time, will be set at subscription creation time. + This can only be set if the customer does not already have a currency + configured. If not set at creation or update time, it will be set at + subscription creation time. + """ + + default_payment_method_id: Optional[str] + """The Orb ID of the payment method to set as this customer's default. + + Pass `null` to clear the customer's default payment method. """ email: Optional[str] @@ -48,10 +76,15 @@ class CustomerUpdateParams(TypedDict, total=False): external_customer_id: Optional[str] """The external customer ID. - This can only be set if empty and the customer has no past or current - subscriptions. + This can only be set if the customer has no existing external customer ID. Since + this action may change usage quantities for all existing subscriptions, it is + disallowed if the customer has issued invoices with usage line items and subject + to the same restrictions as backdated subscription creation. """ + hierarchy: Optional[CustomerHierarchyConfigParam] + """The hierarchical relationships for this customer.""" + metadata: Optional[Dict[str, Optional[str]]] """User-specified key/value pairs for the resource. @@ -62,7 +95,15 @@ class CustomerUpdateParams(TypedDict, total=False): name: Optional[str] """The full name of the customer""" - payment_provider: Optional[Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite"]] + payment_configuration: Optional[PaymentConfiguration] + """ + Payment configuration for the customer, applicable when using Orb Invoicing with + a supported payment provider such as Stripe. + """ + + payment_provider: Optional[ + Literal["quickbooks", "bill.com", "stripe_charge", "stripe_invoice", "netsuite", "adyen"] + ] """This is used for creating charges or invoices in an external system via Orb. When not in test mode: @@ -79,266 +120,241 @@ class CustomerUpdateParams(TypedDict, total=False): This is used for creating charges or invoices in the external system via Orb. """ - reporting_configuration: Optional[ReportingConfiguration] + reporting_configuration: Optional[NewReportingConfigurationParam] - shipping_address: Optional[ShippingAddress] + shipping_address: Optional[AddressInputParam] - tax_id: Optional[TaxID] + tax_configuration: Optional[TaxConfiguration] + + tax_id: Optional[CustomerTaxID] """ Tax IDs are commonly required to be displayed on customer invoices, which are added to the headers of invoices. ### Supported Tax ID Countries and Types - | Country | Type | Description | - | -------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | - | Andorra | `ad_nrt` | Andorran NRT number | - | Australia | `au_abn` | Australian Business Number (AU ABN) | - | Australia | `au_arn` | Australian Taxation Office Reference Number | - | Austria | `eu_vat` | European VAT number | - | Belgium | `eu_vat` | European VAT number | - | Brazil | `br_cnpj` | Brazilian CNPJ number | - | Brazil | `br_cpf` | Brazilian CPF number | - | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | - | Bulgaria | `eu_vat` | European VAT number | - | Canada | `ca_bn` | Canadian BN | - | Canada | `ca_gst_hst` | Canadian GST/HST number | - | Canada | `ca_pst_bc` | Canadian PST number (British Columbia) | - | Canada | `ca_pst_mb` | Canadian PST number (Manitoba) | - | Canada | `ca_pst_sk` | Canadian PST number (Saskatchewan) | - | Canada | `ca_qst` | Canadian QST number (Québec) | - | Chile | `cl_tin` | Chilean TIN | - | Croatia | `eu_vat` | European VAT number | - | Cyprus | `eu_vat` | European VAT number | - | Czech Republic | `eu_vat` | European VAT number | - | Denmark | `eu_vat` | European VAT number | - | Egypt | `eg_tin` | Egyptian Tax Identification Number | - | Estonia | `eu_vat` | European VAT number | - | EU | `eu_oss_vat` | European One Stop Shop VAT number for non-Union scheme | - | Finland | `eu_vat` | European VAT number | - | France | `eu_vat` | European VAT number | - | Georgia | `ge_vat` | Georgian VAT | - | Germany | `eu_vat` | European VAT number | - | Greece | `eu_vat` | European VAT number | - | Hong Kong | `hk_br` | Hong Kong BR number | - | Hungary | `eu_vat` | European VAT number | - | Hungary | `hu_tin` | Hungary tax number (adószám) | - | Iceland | `is_vat` | Icelandic VAT | - | India | `in_gst` | Indian GST number | - | Indonesia | `id_npwp` | Indonesian NPWP number | - | Ireland | `eu_vat` | European VAT number | - | Israel | `il_vat` | Israel VAT | - | Italy | `eu_vat` | European VAT number | - | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | - | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | - | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | - | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | - | Latvia | `eu_vat` | European VAT number | - | Liechtenstein | `li_uid` | Liechtensteinian UID number | - | Lithuania | `eu_vat` | European VAT number | - | Luxembourg | `eu_vat` | European VAT number | - | Malaysia | `my_frp` | Malaysian FRP number | - | Malaysia | `my_itn` | Malaysian ITN | - | Malaysia | `my_sst` | Malaysian SST number | - | Malta | `eu_vat ` | European VAT number | - | Mexico | `mx_rfc` | Mexican RFC number | - | Netherlands | `eu_vat` | European VAT number | - | New Zealand | `nz_gst` | New Zealand GST number | - | Norway | `no_vat` | Norwegian VAT number | - | Philippines | `ph_tin ` | Philippines Tax Identification Number | - | Poland | `eu_vat` | European VAT number | - | Portugal | `eu_vat` | European VAT number | - | Romania | `eu_vat` | European VAT number | - | Russia | `ru_inn` | Russian INN | - | Russia | `ru_kpp` | Russian KPP | - | Saudi Arabia | `sg_gst` | Singaporean GST | - | Singapore | `sg_uen` | Singaporean UEN | - | Slovakia | `eu_vat` | European VAT number | - | Slovenia | `eu_vat` | European VAT number | - | Slovenia | `si_tin` | Slovenia tax number (davčna številka) | - | South Africa | `za_vat` | South African VAT number | - | South Korea | `kr_brn` | Korean BRN | - | Spain | `es_cif` | Spanish NIF number (previously Spanish CIF number) | - | Spain | `eu_vat` | European VAT number | - | Sweden | `eu_vat` | European VAT number | - | Switzerland | `ch_vat` | Switzerland VAT number | - | Taiwan | `tw_vat` | Taiwanese VAT | - | Thailand | `th_vat` | Thai VAT | - | Turkey | `tr_tin` | Turkish Tax Identification Number | - | Ukraine | `ua_vat` | Ukrainian VAT | - | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | - | United Kingdom | `eu_vat` | Northern Ireland VAT number | - | United Kingdom | `gb_vat` | United Kingdom VAT number | - | United States | `us_ein` | United States EIN | + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | """ -class AccountingSyncConfigurationAccountingProvider(TypedDict, total=False): - external_provider_id: Required[str] - - provider_type: Required[str] - - -class AccountingSyncConfiguration(TypedDict, total=False): - accounting_providers: Optional[Iterable[AccountingSyncConfigurationAccountingProvider]] - - excluded: Optional[bool] - - -class BillingAddress(TypedDict, total=False): - city: Optional[str] - - country: Optional[str] - - line1: Optional[str] - - line2: Optional[str] - - postal_code: Optional[str] - - state: Optional[str] - - -class ReportingConfiguration(TypedDict, total=False): - exempt: Required[bool] - - -class ShippingAddress(TypedDict, total=False): - city: Optional[str] - - country: Optional[str] - - line1: Optional[str] - - line2: Optional[str] - - postal_code: Optional[str] - - state: Optional[str] - - -class TaxID(TypedDict, total=False): - country: Required[ - Literal[ - "AD", - "AE", - "AT", - "AU", - "BE", - "BG", - "BR", - "CA", - "CH", - "CL", - "CY", - "CZ", - "DE", - "DK", - "EE", - "EG", - "ES", - "EU", - "FI", - "FR", - "GB", - "GE", - "GR", - "HK", - "HR", - "HU", - "ID", - "IE", - "IL", - "IN", - "IS", - "IT", - "JP", - "KE", - "KR", - "LI", - "LT", - "LU", - "LV", - "MT", - "MX", - "MY", - "NL", - "NO", - "NZ", - "PH", - "PL", - "PT", - "RO", - "RU", - "SA", - "SE", - "SG", - "SI", - "SK", - "TH", - "TR", - "TW", - "UA", - "US", - "ZA", - ] - ] +class PaymentConfigurationPaymentProvider(TypedDict, total=False): + provider_type: Required[Literal["stripe"]] + """The payment provider to configure.""" - type: Required[ - Literal[ - "ad_nrt", - "ae_trn", - "eu_vat", - "au_abn", - "au_arn", - "bg_uic", - "br_cnpj", - "br_cpf", - "ca_bn", - "ca_gst_hst", - "ca_pst_bc", - "ca_pst_mb", - "ca_pst_sk", - "ca_qst", - "ch_vat", - "cl_tin", - "eg_tin", - "es_cif", - "eu_oss_vat", - "gb_vat", - "ge_vat", - "hk_br", - "hu_tin", - "id_npwp", - "il_vat", - "in_gst", - "is_vat", - "jp_cn", - "jp_rn", - "jp_trn", - "ke_pin", - "kr_brn", - "li_uid", - "mx_rfc", - "my_frp", - "my_itn", - "my_sst", - "no_vat", - "nz_gst", - "ph_tin", - "ru_inn", - "ru_kpp", - "sa_vat", - "sg_gst", - "sg_uen", - "si_tin", - "th_vat", - "tr_tin", - "tw_vat", - "ua_vat", - "us_ein", - "za_vat", - ] - ] + default_shared_payment_token: Optional[str] + """ + The ID of a shared payment token granted by an agent to use as the default + payment instrument for this customer. When set, auto-collection will use this + token instead of the customer's default payment method. + """ + + excluded_payment_method_types: SequenceNotStr[str] + """List of Stripe payment method types to exclude for this customer. + + Excluded payment methods will not be available for the customer to select during + payment, and will not be used for auto-collection. If a customer's default + payment method becomes excluded, Orb will attempt to use the next available + compatible payment method for auto-collection. + """ + + +class PaymentConfiguration(TypedDict, total=False): + """ + Payment configuration for the customer, applicable when using Orb Invoicing with a supported payment provider such as Stripe. + """ + + payment_providers: Iterable[PaymentConfigurationPaymentProvider] + """Provider-specific payment configuration.""" + + +class TaxConfigurationNewNumeralConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["numeral"]] + + automatic_tax_enabled: Optional[bool] + """Whether to automatically calculate tax for this customer. + + When null, inherits from account-level setting. When true or false, overrides + the account setting. + """ + + +class TaxConfigurationNewAnrokConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["anrok"]] - value: Required[str] + automatic_tax_enabled: Optional[bool] + """Whether to automatically calculate tax for this customer. + + When null, inherits from account-level setting. When true or false, overrides + the account setting. + """ + + +class TaxConfigurationNewStripeTaxConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["stripe"]] + + automatic_tax_enabled: Optional[bool] + """Whether to automatically calculate tax for this customer. + + When null, inherits from account-level setting. When true or false, overrides + the account setting. + """ + + +TaxConfiguration: TypeAlias = Union[ + NewAvalaraTaxConfigurationParam, + NewTaxJarConfigurationParam, + NewSphereConfigurationParam, + TaxConfigurationNewNumeralConfiguration, + TaxConfigurationNewAnrokConfiguration, + TaxConfigurationNewStripeTaxConfiguration, +] diff --git a/src/orb/types/customers/__init__.py b/src/orb/types/customers/__init__.py index c144cc46..ba43a9b2 100644 --- a/src/orb/types/customers/__init__.py +++ b/src/orb/types/customers/__init__.py @@ -5,16 +5,12 @@ from .cost_list_params import CostListParams as CostListParams from .cost_list_response import CostListResponse as CostListResponse from .credit_list_params import CreditListParams as CreditListParams -from .usage_update_params import UsageUpdateParams as UsageUpdateParams from .credit_list_response import CreditListResponse as CreditListResponse -from .usage_update_response import UsageUpdateResponse as UsageUpdateResponse from .balance_transaction_list_params import BalanceTransactionListParams as BalanceTransactionListParams from .cost_list_by_external_id_params import CostListByExternalIDParams as CostListByExternalIDParams from .balance_transaction_create_params import BalanceTransactionCreateParams as BalanceTransactionCreateParams from .balance_transaction_list_response import BalanceTransactionListResponse as BalanceTransactionListResponse from .cost_list_by_external_id_response import CostListByExternalIDResponse as CostListByExternalIDResponse from .credit_list_by_external_id_params import CreditListByExternalIDParams as CreditListByExternalIDParams -from .usage_update_by_external_id_params import UsageUpdateByExternalIDParams as UsageUpdateByExternalIDParams from .balance_transaction_create_response import BalanceTransactionCreateResponse as BalanceTransactionCreateResponse from .credit_list_by_external_id_response import CreditListByExternalIDResponse as CreditListByExternalIDResponse -from .usage_update_by_external_id_response import UsageUpdateByExternalIDResponse as UsageUpdateByExternalIDResponse diff --git a/src/orb/types/customers/balance_transaction_create_response.py b/src/orb/types/customers/balance_transaction_create_response.py index 09f688d0..1141d365 100644 --- a/src/orb/types/customers/balance_transaction_create_response.py +++ b/src/orb/types/customers/balance_transaction_create_response.py @@ -5,18 +5,10 @@ from typing_extensions import Literal from ..._models import BaseModel +from ..shared.invoice_tiny import InvoiceTiny +from ..shared.credit_note_tiny import CreditNoteTiny -__all__ = ["BalanceTransactionCreateResponse", "CreditNote", "Invoice"] - - -class CreditNote(BaseModel): - id: str - """The id of the Credit note""" - - -class Invoice(BaseModel): - id: str - """The Invoice id""" +__all__ = ["BalanceTransactionCreateResponse"] class BalanceTransactionCreateResponse(BaseModel): @@ -32,6 +24,8 @@ class BalanceTransactionCreateResponse(BaseModel): "credit_note_applied", "credit_note_voided", "overpayment_refund", + "external_payment", + "small_invoice_carryover", ] amount: str @@ -40,7 +34,7 @@ class BalanceTransactionCreateResponse(BaseModel): created_at: datetime """The creation time of this transaction.""" - credit_note: Optional[CreditNote] = None + credit_note: Optional[CreditNoteTiny] = None description: Optional[str] = None """An optional description provided for manual customer balance adjustments.""" @@ -51,7 +45,7 @@ class BalanceTransactionCreateResponse(BaseModel): customer's currency. """ - invoice: Optional[Invoice] = None + invoice: Optional[InvoiceTiny] = None starting_balance: str """ diff --git a/src/orb/types/customers/balance_transaction_list_response.py b/src/orb/types/customers/balance_transaction_list_response.py index d5d3bb38..ac3ccea8 100644 --- a/src/orb/types/customers/balance_transaction_list_response.py +++ b/src/orb/types/customers/balance_transaction_list_response.py @@ -5,18 +5,10 @@ from typing_extensions import Literal from ..._models import BaseModel +from ..shared.invoice_tiny import InvoiceTiny +from ..shared.credit_note_tiny import CreditNoteTiny -__all__ = ["BalanceTransactionListResponse", "CreditNote", "Invoice"] - - -class CreditNote(BaseModel): - id: str - """The id of the Credit note""" - - -class Invoice(BaseModel): - id: str - """The Invoice id""" +__all__ = ["BalanceTransactionListResponse"] class BalanceTransactionListResponse(BaseModel): @@ -32,6 +24,8 @@ class BalanceTransactionListResponse(BaseModel): "credit_note_applied", "credit_note_voided", "overpayment_refund", + "external_payment", + "small_invoice_carryover", ] amount: str @@ -40,7 +34,7 @@ class BalanceTransactionListResponse(BaseModel): created_at: datetime """The creation time of this transaction.""" - credit_note: Optional[CreditNote] = None + credit_note: Optional[CreditNoteTiny] = None description: Optional[str] = None """An optional description provided for manual customer balance adjustments.""" @@ -51,7 +45,7 @@ class BalanceTransactionListResponse(BaseModel): customer's currency. """ - invoice: Optional[Invoice] = None + invoice: Optional[InvoiceTiny] = None starting_balance: str """ diff --git a/src/orb/types/customers/cost_list_by_external_id_params.py b/src/orb/types/customers/cost_list_by_external_id_params.py index 9455e18e..dad37e47 100644 --- a/src/orb/types/customers/cost_list_by_external_id_params.py +++ b/src/orb/types/customers/cost_list_by_external_id_params.py @@ -12,6 +12,9 @@ class CostListByExternalIDParams(TypedDict, total=False): + currency: Optional[str] + """The currency or custom pricing unit to use.""" + timeframe_end: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] """Costs returned are exclusive of `timeframe_end`.""" diff --git a/src/orb/types/customers/cost_list_by_external_id_response.py b/src/orb/types/customers/cost_list_by_external_id_response.py index 8345151d..27b8ee21 100644 --- a/src/orb/types/customers/cost_list_by_external_id_response.py +++ b/src/orb/types/customers/cost_list_by_external_id_response.py @@ -1,273 +1,12 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional -from datetime import datetime +from typing import List -from ..price import Price from ..._models import BaseModel +from ..shared.aggregated_cost import AggregatedCost -__all__ = ["CostListByExternalIDResponse", "Data", "DataPerPriceCost"] - - -class DataPerPriceCost(BaseModel): - 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 - ... - } - ``` - """ - - subtotal: str - """Price's contributions for the timeframe, excluding any minimums and discounts.""" - - total: str - """Price's contributions for the timeframe, including minimums and discounts.""" - - quantity: Optional[float] = None - """The price's quantity for the timeframe""" - - -class Data(BaseModel): - per_price_costs: List[DataPerPriceCost] - - subtotal: str - """Total costs for the timeframe, excluding any minimums and discounts.""" - - timeframe_end: datetime - - timeframe_start: datetime - - total: str - """Total costs for the timeframe, including any minimums and discounts.""" +__all__ = ["CostListByExternalIDResponse"] class CostListByExternalIDResponse(BaseModel): - data: List[Data] + data: List[AggregatedCost] diff --git a/src/orb/types/customers/cost_list_params.py b/src/orb/types/customers/cost_list_params.py index 041cf861..741fd8d9 100644 --- a/src/orb/types/customers/cost_list_params.py +++ b/src/orb/types/customers/cost_list_params.py @@ -12,6 +12,9 @@ class CostListParams(TypedDict, total=False): + currency: Optional[str] + """The currency or custom pricing unit to use.""" + timeframe_end: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] """Costs returned are exclusive of `timeframe_end`.""" diff --git a/src/orb/types/customers/cost_list_response.py b/src/orb/types/customers/cost_list_response.py index fe384554..3e424b09 100644 --- a/src/orb/types/customers/cost_list_response.py +++ b/src/orb/types/customers/cost_list_response.py @@ -1,273 +1,12 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional -from datetime import datetime +from typing import List -from ..price import Price from ..._models import BaseModel +from ..shared.aggregated_cost import AggregatedCost -__all__ = ["CostListResponse", "Data", "DataPerPriceCost"] - - -class DataPerPriceCost(BaseModel): - 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 - ... - } - ``` - """ - - subtotal: str - """Price's contributions for the timeframe, excluding any minimums and discounts.""" - - total: str - """Price's contributions for the timeframe, including minimums and discounts.""" - - quantity: Optional[float] = None - """The price's quantity for the timeframe""" - - -class Data(BaseModel): - per_price_costs: List[DataPerPriceCost] - - subtotal: str - """Total costs for the timeframe, excluding any minimums and discounts.""" - - timeframe_end: datetime - - timeframe_start: datetime - - total: str - """Total costs for the timeframe, including any minimums and discounts.""" +__all__ = ["CostListResponse"] class CostListResponse(BaseModel): - data: List[Data] + data: List[AggregatedCost] diff --git a/src/orb/types/customers/credit_list_by_external_id_params.py b/src/orb/types/customers/credit_list_by_external_id_params.py index b4b3cc5a..0d32d3c5 100644 --- a/src/orb/types/customers/credit_list_by_external_id_params.py +++ b/src/orb/types/customers/credit_list_by_external_id_params.py @@ -2,8 +2,11 @@ from __future__ import annotations -from typing import Optional -from typing_extensions import TypedDict +from typing import Union, Optional +from datetime import datetime +from typing_extensions import Annotated, TypedDict + +from ..._utils import PropertyInfo __all__ = ["CreditListByExternalIDParams"] @@ -19,5 +22,23 @@ class CreditListByExternalIDParams(TypedDict, total=False): request. """ + effective_date_gt: Annotated[Union[str, datetime, None], PropertyInfo(alias="effective_date[gt]", format="iso8601")] + + effective_date_gte: Annotated[ + Union[str, datetime, None], PropertyInfo(alias="effective_date[gte]", format="iso8601") + ] + + effective_date_lt: Annotated[Union[str, datetime, None], PropertyInfo(alias="effective_date[lt]", format="iso8601")] + + effective_date_lte: Annotated[ + Union[str, datetime, None], PropertyInfo(alias="effective_date[lte]", format="iso8601") + ] + + include_all_blocks: bool + """ + If set to True, all expired and depleted blocks, as well as active block will be + returned. + """ + limit: int """The number of items to fetch. Defaults to 20.""" diff --git a/src/orb/types/customers/credit_list_by_external_id_response.py b/src/orb/types/customers/credit_list_by_external_id_response.py index 9d8f6d2c..5895cd48 100644 --- a/src/orb/types/customers/credit_list_by_external_id_response.py +++ b/src/orb/types/customers/credit_list_by_external_id_response.py @@ -1,12 +1,61 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import Dict, List, Optional from datetime import datetime from typing_extensions import Literal from ..._models import BaseModel +from ..shared.custom_expiration import CustomExpiration -__all__ = ["CreditListByExternalIDResponse"] +__all__ = ["CreditListByExternalIDResponse", "Filter", "CreditAllocation", "CreditAllocationFilter"] + + +class Filter(BaseModel): + """A PriceFilter that only allows item_id field for block filters.""" + + field: Literal["item_id"] + """The property of the price the block applies to. Only item_id is supported.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class CreditAllocationFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class CreditAllocation(BaseModel): + """The credit allocation that funded a block. + + Extends the allocation resource + serialized on prices with the catalog-item attribution of the funding price. + """ + + allows_rollover: bool + + currency: str + + custom_expiration: Optional[CustomExpiration] = None + + item_id: str + """ + The ID of the catalog item this block was allocated from, derived from the + allocation's price. + """ + + filters: Optional[List[CreditAllocationFilter]] = None + + license_type_id: Optional[str] = None class CreditListByExternalIDResponse(BaseModel): @@ -14,8 +63,37 @@ class CreditListByExternalIDResponse(BaseModel): balance: float + credit_block_source: Literal["allocation", "top_up", "manual"] + """ + How this credit block was created: `allocation` (a subscription's recurring + credit allocation), `top_up` (an automatic balance-threshold top-up), or + `manual` (a manual credit ledger increment, including credits voided or expired + off another block). + """ + + effective_date: Optional[datetime] = None + expiry_date: Optional[datetime] = None + filters: List[Filter] + + maximum_initial_balance: Optional[float] = 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`. + """ + per_unit_cost_basis: Optional[str] = None status: Literal["active", "pending_payment"] + + credit_allocation: Optional[CreditAllocation] = None + """The credit allocation that funded a block. + + Extends the allocation resource serialized on prices with the catalog-item + attribution of the funding price. + """ diff --git a/src/orb/types/customers/credit_list_params.py b/src/orb/types/customers/credit_list_params.py index 64527331..80c44d5b 100644 --- a/src/orb/types/customers/credit_list_params.py +++ b/src/orb/types/customers/credit_list_params.py @@ -2,8 +2,11 @@ from __future__ import annotations -from typing import Optional -from typing_extensions import TypedDict +from typing import Union, Optional +from datetime import datetime +from typing_extensions import Annotated, TypedDict + +from ..._utils import PropertyInfo __all__ = ["CreditListParams"] @@ -19,5 +22,23 @@ class CreditListParams(TypedDict, total=False): request. """ + effective_date_gt: Annotated[Union[str, datetime, None], PropertyInfo(alias="effective_date[gt]", format="iso8601")] + + effective_date_gte: Annotated[ + Union[str, datetime, None], PropertyInfo(alias="effective_date[gte]", format="iso8601") + ] + + effective_date_lt: Annotated[Union[str, datetime, None], PropertyInfo(alias="effective_date[lt]", format="iso8601")] + + effective_date_lte: Annotated[ + Union[str, datetime, None], PropertyInfo(alias="effective_date[lte]", format="iso8601") + ] + + include_all_blocks: bool + """ + If set to True, all expired and depleted blocks, as well as active block will be + returned. + """ + limit: int """The number of items to fetch. Defaults to 20.""" diff --git a/src/orb/types/customers/credit_list_response.py b/src/orb/types/customers/credit_list_response.py index 494c10e0..7122af1d 100644 --- a/src/orb/types/customers/credit_list_response.py +++ b/src/orb/types/customers/credit_list_response.py @@ -1,12 +1,61 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import Dict, List, Optional from datetime import datetime from typing_extensions import Literal from ..._models import BaseModel +from ..shared.custom_expiration import CustomExpiration -__all__ = ["CreditListResponse"] +__all__ = ["CreditListResponse", "Filter", "CreditAllocation", "CreditAllocationFilter"] + + +class Filter(BaseModel): + """A PriceFilter that only allows item_id field for block filters.""" + + field: Literal["item_id"] + """The property of the price the block applies to. Only item_id is supported.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class CreditAllocationFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class CreditAllocation(BaseModel): + """The credit allocation that funded a block. + + Extends the allocation resource + serialized on prices with the catalog-item attribution of the funding price. + """ + + allows_rollover: bool + + currency: str + + custom_expiration: Optional[CustomExpiration] = None + + item_id: str + """ + The ID of the catalog item this block was allocated from, derived from the + allocation's price. + """ + + filters: Optional[List[CreditAllocationFilter]] = None + + license_type_id: Optional[str] = None class CreditListResponse(BaseModel): @@ -14,8 +63,37 @@ class CreditListResponse(BaseModel): balance: float + credit_block_source: Literal["allocation", "top_up", "manual"] + """ + How this credit block was created: `allocation` (a subscription's recurring + credit allocation), `top_up` (an automatic balance-threshold top-up), or + `manual` (a manual credit ledger increment, including credits voided or expired + off another block). + """ + + effective_date: Optional[datetime] = None + expiry_date: Optional[datetime] = None + filters: List[Filter] + + maximum_initial_balance: Optional[float] = 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`. + """ + per_unit_cost_basis: Optional[str] = None status: Literal["active", "pending_payment"] + + credit_allocation: Optional[CreditAllocation] = None + """The credit allocation that funded a block. + + Extends the allocation resource serialized on prices with the catalog-item + attribution of the funding price. + """ diff --git a/src/orb/types/customers/credits/__init__.py b/src/orb/types/customers/credits/__init__.py index 9baa17d8..d5d304d6 100644 --- a/src/orb/types/customers/credits/__init__.py +++ b/src/orb/types/customers/credits/__init__.py @@ -2,14 +2,23 @@ from __future__ import annotations +from .affected_block import AffectedBlock as AffectedBlock +from .void_ledger_entry import VoidLedgerEntry as VoidLedgerEntry from .ledger_list_params import LedgerListParams as LedgerListParams from .top_up_list_params import TopUpListParams as TopUpListParams from .ledger_list_response import LedgerListResponse as LedgerListResponse from .top_up_create_params import TopUpCreateParams as TopUpCreateParams from .top_up_list_response import TopUpListResponse as TopUpListResponse +from .amendment_ledger_entry import AmendmentLedgerEntry as AmendmentLedgerEntry +from .decrement_ledger_entry import DecrementLedgerEntry as DecrementLedgerEntry +from .increment_ledger_entry import IncrementLedgerEntry as IncrementLedgerEntry from .top_up_create_response import TopUpCreateResponse as TopUpCreateResponse +from .top_up_invoice_settings import TopUpInvoiceSettings as TopUpInvoiceSettings from .ledger_create_entry_params import LedgerCreateEntryParams as LedgerCreateEntryParams +from .void_initiated_ledger_entry import VoidInitiatedLedgerEntry as VoidInitiatedLedgerEntry from .ledger_create_entry_response import LedgerCreateEntryResponse as LedgerCreateEntryResponse +from .expiration_change_ledger_entry import ExpirationChangeLedgerEntry as ExpirationChangeLedgerEntry +from .credit_block_expiry_ledger_entry import CreditBlockExpiryLedgerEntry as CreditBlockExpiryLedgerEntry from .ledger_list_by_external_id_params import LedgerListByExternalIDParams as LedgerListByExternalIDParams from .top_up_list_by_external_id_params import TopUpListByExternalIDParams as TopUpListByExternalIDParams from .ledger_list_by_external_id_response import LedgerListByExternalIDResponse as LedgerListByExternalIDResponse diff --git a/src/orb/types/customers/credits/affected_block.py b/src/orb/types/customers/credits/affected_block.py new file mode 100644 index 00000000..74b2b925 --- /dev/null +++ b/src/orb/types/customers/credits/affected_block.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["AffectedBlock", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class AffectedBlock(BaseModel): + id: str + + expiry_date: Optional[datetime] = None + + filters: List[Filter] + + per_unit_cost_basis: Optional[str] = None diff --git a/src/orb/types/customers/credits/amendment_ledger_entry.py b/src/orb/types/customers/credits/amendment_ledger_entry.py new file mode 100644 index 00000000..9030f9ee --- /dev/null +++ b/src/orb/types/customers/credits/amendment_ledger_entry.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel +from .affected_block import AffectedBlock +from ...shared.customer_minified import CustomerMinified + +__all__ = ["AmendmentLedgerEntry"] + + +class AmendmentLedgerEntry(BaseModel): + id: str + + amount: float + + created_at: datetime + + credit_block: AffectedBlock + + currency: str + + customer: CustomerMinified + + description: Optional[str] = None + + ending_balance: float + + entry_status: Literal["committed", "pending"] + + entry_type: Literal["amendment"] + + ledger_sequence_number: int + + 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`. + """ + + starting_balance: float diff --git a/src/orb/types/customers/credits/credit_block_expiry_ledger_entry.py b/src/orb/types/customers/credits/credit_block_expiry_ledger_entry.py new file mode 100644 index 00000000..f13127a1 --- /dev/null +++ b/src/orb/types/customers/credits/credit_block_expiry_ledger_entry.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel +from .affected_block import AffectedBlock +from ...shared.customer_minified import CustomerMinified + +__all__ = ["CreditBlockExpiryLedgerEntry"] + + +class CreditBlockExpiryLedgerEntry(BaseModel): + id: str + + amount: float + + created_at: datetime + + credit_block: AffectedBlock + + currency: str + + customer: CustomerMinified + + description: Optional[str] = None + + ending_balance: float + + entry_status: Literal["committed", "pending"] + + entry_type: Literal["credit_block_expiry"] + + ledger_sequence_number: int + + 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`. + """ + + starting_balance: float diff --git a/src/orb/types/customers/credits/decrement_ledger_entry.py b/src/orb/types/customers/credits/decrement_ledger_entry.py new file mode 100644 index 00000000..3f0896c2 --- /dev/null +++ b/src/orb/types/customers/credits/decrement_ledger_entry.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel +from .affected_block import AffectedBlock +from ...shared.customer_minified import CustomerMinified + +__all__ = ["DecrementLedgerEntry"] + + +class DecrementLedgerEntry(BaseModel): + id: str + + amount: float + + created_at: datetime + + credit_block: AffectedBlock + + currency: str + + customer: CustomerMinified + + description: Optional[str] = None + + ending_balance: float + + entry_status: Literal["committed", "pending"] + + entry_type: Literal["decrement"] + + ledger_sequence_number: int + + 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`. + """ + + starting_balance: float + + event_id: Optional[str] = None + """This field is deprecated and will always be null. + + Decrements are not associated with individual events. + """ + + invoice_id: Optional[str] = None + + price_id: Optional[str] = None diff --git a/src/orb/types/customers/credits/expiration_change_ledger_entry.py b/src/orb/types/customers/credits/expiration_change_ledger_entry.py new file mode 100644 index 00000000..c1cbfa21 --- /dev/null +++ b/src/orb/types/customers/credits/expiration_change_ledger_entry.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel +from .affected_block import AffectedBlock +from ...shared.customer_minified import CustomerMinified + +__all__ = ["ExpirationChangeLedgerEntry"] + + +class ExpirationChangeLedgerEntry(BaseModel): + id: str + + amount: float + + created_at: datetime + + credit_block: AffectedBlock + + currency: str + + customer: CustomerMinified + + description: Optional[str] = None + + ending_balance: float + + entry_status: Literal["committed", "pending"] + + entry_type: Literal["expiration_change"] + + ledger_sequence_number: int + + 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`. + """ + + new_block_expiry_date: Optional[datetime] = None + + starting_balance: float diff --git a/src/orb/types/customers/credits/increment_ledger_entry.py b/src/orb/types/customers/credits/increment_ledger_entry.py new file mode 100644 index 00000000..cc57d922 --- /dev/null +++ b/src/orb/types/customers/credits/increment_ledger_entry.py @@ -0,0 +1,49 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel +from .affected_block import AffectedBlock +from ...shared.invoice import Invoice +from ...shared.customer_minified import CustomerMinified + +__all__ = ["IncrementLedgerEntry"] + + +class IncrementLedgerEntry(BaseModel): + id: str + + amount: float + + created_at: datetime + + credit_block: AffectedBlock + + currency: str + + customer: CustomerMinified + + description: Optional[str] = None + + ending_balance: float + + entry_status: Literal["committed", "pending"] + + entry_type: Literal["increment"] + + ledger_sequence_number: int + + 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`. + """ + + starting_balance: float + + created_invoices: Optional[List[Invoice]] = None + """If the increment resulted in invoice creation, the list of created invoices""" diff --git a/src/orb/types/customers/credits/ledger_create_entry_by_external_id_params.py b/src/orb/types/customers/credits/ledger_create_entry_by_external_id_params.py index 02a60ac4..37c7f2b5 100644 --- a/src/orb/types/customers/credits/ledger_create_entry_by_external_id_params.py +++ b/src/orb/types/customers/credits/ledger_create_entry_by_external_id_params.py @@ -2,15 +2,17 @@ from __future__ import annotations -from typing import Dict, Union, Optional +from typing import Dict, Union, Iterable, Optional from datetime import date, datetime -from typing_extensions import Literal, Required, Annotated, TypedDict +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict +from ...._types import SequenceNotStr from ...._utils import PropertyInfo __all__ = [ "LedgerCreateEntryByExternalIDParams", "AddIncrementCreditLedgerEntryRequestParams", + "AddIncrementCreditLedgerEntryRequestParamsFilter", "AddIncrementCreditLedgerEntryRequestParamsInvoiceSettings", "AddDecrementCreditLedgerEntryRequestParams", "AddExpirationChangeCreditLedgerEntryRequestParams", @@ -51,6 +53,12 @@ class AddIncrementCreditLedgerEntryRequestParams(TypedDict, total=False): expiry_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] """An ISO 8601 format date that denotes when this credit balance should expire.""" + filters: Optional[Iterable[AddIncrementCreditLedgerEntryRequestParamsFilter]] + """Optional filter to specify which items this credit block applies to. + + If not specified, the block will apply to all items for the pricing unit. + """ + invoice_settings: Optional[AddIncrementCreditLedgerEntryRequestParamsInvoiceSettings] """ Passing `invoice_settings` automatically generates an invoice for the newly @@ -69,27 +77,76 @@ class AddIncrementCreditLedgerEntryRequestParams(TypedDict, total=False): per_unit_cost_basis: Optional[str] """Can only be specified when entry_type=increment. - How much, in USD, a customer paid for a single credit in this block + How much, in the customer's currency, a customer paid for a single credit in + this block """ +class AddIncrementCreditLedgerEntryRequestParamsFilter(TypedDict, total=False): + """A PriceFilter that only allows item_id field for block filters.""" + + field: Required[Literal["item_id"]] + """The property of the price the block applies to. Only item_id is supported.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + class AddIncrementCreditLedgerEntryRequestParamsInvoiceSettings(TypedDict, total=False): + """ + Passing `invoice_settings` automatically generates an invoice for the newly added credits. If `invoice_settings` is passed, you must specify per_unit_cost_basis, as the calculation of the invoice total is done on that basis. + """ + auto_collection: Required[bool] """ Whether the credits purchase invoice should auto collect with the customer's saved payment method. """ - net_terms: Required[int] + custom_due_date: Annotated[Union[Union[str, date], Union[str, datetime], None], PropertyInfo(format="iso8601")] + """An optional custom due date for the invoice. + + If not set, the due date will be calculated based on the `net_terms` value. """ - The net terms determines the difference between the invoice date and the issue - date for the invoice. If you intend the invoice to be due on issue, set this - to 0. + + invoice_date: Annotated[Union[Union[str, date], Union[str, datetime], None], PropertyInfo(format="iso8601")] + """ + An ISO 8601 format date that denotes when this invoice should be dated in the + customer's timezone. If not provided, the invoice date will default to the + credit block's effective date. """ + item_id: Optional[str] + """The ID of the Item to be used for the invoice line item. + + If not provided, a default 'Credits' item will be used. + """ + + mark_as_paid: bool + """If true, the new credits purchase invoice will be marked as paid.""" + memo: Optional[str] """An optional memo to display on the invoice.""" + net_terms: Optional[int] + """The net terms determines the due date of the invoice. + + Due date is calculated based on the invoice or issuance date, depending on the + account's configured due date calculation method. A value of '0' here represents + that the invoice is due on issue, whereas a value of '30' represents that the + customer has 30 days to pay the invoice. You must set either `net_terms` or + `custom_due_date`, but not both. + """ + + require_successful_payment: bool + """ + If true, the new credit block will require that the corresponding invoice is + paid before it can be drawn down from. + """ + class AddDecrementCreditLedgerEntryRequestParams(TypedDict, total=False): amount: Required[float] @@ -125,14 +182,11 @@ class AddDecrementCreditLedgerEntryRequestParams(TypedDict, total=False): class AddExpirationChangeCreditLedgerEntryRequestParams(TypedDict, total=False): entry_type: Required[Literal["expiration_change"]] - expiry_date: Required[Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]] - """An ISO 8601 format date that identifies the origination credit block to expire""" - target_expiry_date: Required[Annotated[Union[str, date], PropertyInfo(format="iso8601")]] """ - A future date (specified in YYYY-MM-DD format) used for expiration change, - denoting when credits transferred (as part of a partial block expiration) should - expire. + A date (specified in YYYY-MM-DD format) used for expiration change, denoting + when credits transferred (as part of a partial block expiration) should expire. + This date must be on or after the effective date of the credit block. """ amount: Optional[float] @@ -161,6 +215,9 @@ class AddExpirationChangeCreditLedgerEntryRequestParams(TypedDict, total=False): for noting corrections as a result of an incident, etc. """ + expiry_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """An ISO 8601 format date that identifies the origination credit block to expire""" + metadata: Optional[Dict[str, Optional[str]]] """User-specified key/value pairs for the resource. @@ -240,7 +297,7 @@ class AddAmendmentCreditLedgerEntryRequestParams(TypedDict, total=False): """ -LedgerCreateEntryByExternalIDParams = Union[ +LedgerCreateEntryByExternalIDParams: TypeAlias = Union[ AddIncrementCreditLedgerEntryRequestParams, AddDecrementCreditLedgerEntryRequestParams, AddExpirationChangeCreditLedgerEntryRequestParams, 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 48968b41..ff4f381f 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 @@ -1,397 +1,28 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, Union, Optional -from datetime import datetime -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = [ - "LedgerCreateEntryByExternalIDResponse", - "IncrementLedgerEntry", - "IncrementLedgerEntryCreditBlock", - "IncrementLedgerEntryCustomer", - "DecrementLedgerEntry", - "DecrementLedgerEntryCreditBlock", - "DecrementLedgerEntryCustomer", - "ExpirationChangeLedgerEntry", - "ExpirationChangeLedgerEntryCreditBlock", - "ExpirationChangeLedgerEntryCustomer", - "CreditBlockExpiryLedgerEntry", - "CreditBlockExpiryLedgerEntryCreditBlock", - "CreditBlockExpiryLedgerEntryCustomer", - "VoidLedgerEntry", - "VoidLedgerEntryCreditBlock", - "VoidLedgerEntryCustomer", - "VoidInitiatedLedgerEntry", - "VoidInitiatedLedgerEntryCreditBlock", - "VoidInitiatedLedgerEntryCustomer", - "AmendmentLedgerEntry", - "AmendmentLedgerEntryCreditBlock", - "AmendmentLedgerEntryCustomer", -] - - -class IncrementLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class IncrementLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class IncrementLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: IncrementLedgerEntryCreditBlock - - currency: str - - customer: IncrementLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["increment"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - -class DecrementLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class DecrementLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class DecrementLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: DecrementLedgerEntryCreditBlock - - currency: str - - customer: DecrementLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["decrement"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - event_id: Optional[str] = None - - invoice_id: Optional[str] = None - - price_id: Optional[str] = None - - -class ExpirationChangeLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class ExpirationChangeLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class ExpirationChangeLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: ExpirationChangeLedgerEntryCreditBlock - - currency: str - - customer: ExpirationChangeLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["expiration_change"] - - ledger_sequence_number: int - - 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`. - """ - - new_block_expiry_date: datetime - - starting_balance: float - - -class CreditBlockExpiryLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class CreditBlockExpiryLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class CreditBlockExpiryLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: CreditBlockExpiryLedgerEntryCreditBlock - - currency: str - - customer: CreditBlockExpiryLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["credit_block_expiry"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - -class VoidLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class VoidLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class VoidLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: VoidLedgerEntryCreditBlock - - currency: str - - customer: VoidLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["void"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - void_amount: float - - void_reason: Optional[str] = None - - -class VoidInitiatedLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class VoidInitiatedLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class VoidInitiatedLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: VoidInitiatedLedgerEntryCreditBlock - - currency: str - - customer: VoidInitiatedLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["void_initiated"] - - ledger_sequence_number: int - - 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`. - """ - - new_block_expiry_date: datetime - - starting_balance: float - - void_amount: float - - void_reason: Optional[str] = None - - -class AmendmentLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class AmendmentLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class AmendmentLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: AmendmentLedgerEntryCreditBlock - - currency: str - - customer: AmendmentLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["amendment"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - -LedgerCreateEntryByExternalIDResponse = Union[ - IncrementLedgerEntry, - DecrementLedgerEntry, - ExpirationChangeLedgerEntry, - CreditBlockExpiryLedgerEntry, - VoidLedgerEntry, - VoidInitiatedLedgerEntry, - AmendmentLedgerEntry, +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ...._utils import PropertyInfo +from .void_ledger_entry import VoidLedgerEntry +from .amendment_ledger_entry import AmendmentLedgerEntry +from .decrement_ledger_entry import DecrementLedgerEntry +from .increment_ledger_entry import IncrementLedgerEntry +from .void_initiated_ledger_entry import VoidInitiatedLedgerEntry +from .expiration_change_ledger_entry import ExpirationChangeLedgerEntry +from .credit_block_expiry_ledger_entry import CreditBlockExpiryLedgerEntry + +__all__ = ["LedgerCreateEntryByExternalIDResponse"] + +LedgerCreateEntryByExternalIDResponse: TypeAlias = Annotated[ + Union[ + IncrementLedgerEntry, + DecrementLedgerEntry, + ExpirationChangeLedgerEntry, + CreditBlockExpiryLedgerEntry, + VoidLedgerEntry, + VoidInitiatedLedgerEntry, + AmendmentLedgerEntry, + ], + PropertyInfo(discriminator="entry_type"), ] diff --git a/src/orb/types/customers/credits/ledger_create_entry_params.py b/src/orb/types/customers/credits/ledger_create_entry_params.py index 45734161..f52c8ad2 100644 --- a/src/orb/types/customers/credits/ledger_create_entry_params.py +++ b/src/orb/types/customers/credits/ledger_create_entry_params.py @@ -2,15 +2,17 @@ from __future__ import annotations -from typing import Dict, Union, Optional +from typing import Dict, Union, Iterable, Optional from datetime import date, datetime -from typing_extensions import Literal, Required, Annotated, TypedDict +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict +from ...._types import SequenceNotStr from ...._utils import PropertyInfo __all__ = [ "LedgerCreateEntryParams", "AddIncrementCreditLedgerEntryRequestParams", + "AddIncrementCreditLedgerEntryRequestParamsFilter", "AddIncrementCreditLedgerEntryRequestParamsInvoiceSettings", "AddDecrementCreditLedgerEntryRequestParams", "AddExpirationChangeCreditLedgerEntryRequestParams", @@ -51,6 +53,12 @@ class AddIncrementCreditLedgerEntryRequestParams(TypedDict, total=False): expiry_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] """An ISO 8601 format date that denotes when this credit balance should expire.""" + filters: Optional[Iterable[AddIncrementCreditLedgerEntryRequestParamsFilter]] + """Optional filter to specify which items this credit block applies to. + + If not specified, the block will apply to all items for the pricing unit. + """ + invoice_settings: Optional[AddIncrementCreditLedgerEntryRequestParamsInvoiceSettings] """ Passing `invoice_settings` automatically generates an invoice for the newly @@ -69,27 +77,76 @@ class AddIncrementCreditLedgerEntryRequestParams(TypedDict, total=False): per_unit_cost_basis: Optional[str] """Can only be specified when entry_type=increment. - How much, in USD, a customer paid for a single credit in this block + How much, in the customer's currency, a customer paid for a single credit in + this block """ +class AddIncrementCreditLedgerEntryRequestParamsFilter(TypedDict, total=False): + """A PriceFilter that only allows item_id field for block filters.""" + + field: Required[Literal["item_id"]] + """The property of the price the block applies to. Only item_id is supported.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + class AddIncrementCreditLedgerEntryRequestParamsInvoiceSettings(TypedDict, total=False): + """ + Passing `invoice_settings` automatically generates an invoice for the newly added credits. If `invoice_settings` is passed, you must specify per_unit_cost_basis, as the calculation of the invoice total is done on that basis. + """ + auto_collection: Required[bool] """ Whether the credits purchase invoice should auto collect with the customer's saved payment method. """ - net_terms: Required[int] + custom_due_date: Annotated[Union[Union[str, date], Union[str, datetime], None], PropertyInfo(format="iso8601")] + """An optional custom due date for the invoice. + + If not set, the due date will be calculated based on the `net_terms` value. """ - The net terms determines the difference between the invoice date and the issue - date for the invoice. If you intend the invoice to be due on issue, set this - to 0. + + invoice_date: Annotated[Union[Union[str, date], Union[str, datetime], None], PropertyInfo(format="iso8601")] + """ + An ISO 8601 format date that denotes when this invoice should be dated in the + customer's timezone. If not provided, the invoice date will default to the + credit block's effective date. """ + item_id: Optional[str] + """The ID of the Item to be used for the invoice line item. + + If not provided, a default 'Credits' item will be used. + """ + + mark_as_paid: bool + """If true, the new credits purchase invoice will be marked as paid.""" + memo: Optional[str] """An optional memo to display on the invoice.""" + net_terms: Optional[int] + """The net terms determines the due date of the invoice. + + Due date is calculated based on the invoice or issuance date, depending on the + account's configured due date calculation method. A value of '0' here represents + that the invoice is due on issue, whereas a value of '30' represents that the + customer has 30 days to pay the invoice. You must set either `net_terms` or + `custom_due_date`, but not both. + """ + + require_successful_payment: bool + """ + If true, the new credit block will require that the corresponding invoice is + paid before it can be drawn down from. + """ + class AddDecrementCreditLedgerEntryRequestParams(TypedDict, total=False): amount: Required[float] @@ -125,14 +182,11 @@ class AddDecrementCreditLedgerEntryRequestParams(TypedDict, total=False): class AddExpirationChangeCreditLedgerEntryRequestParams(TypedDict, total=False): entry_type: Required[Literal["expiration_change"]] - expiry_date: Required[Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]] - """An ISO 8601 format date that identifies the origination credit block to expire""" - target_expiry_date: Required[Annotated[Union[str, date], PropertyInfo(format="iso8601")]] """ - A future date (specified in YYYY-MM-DD format) used for expiration change, - denoting when credits transferred (as part of a partial block expiration) should - expire. + A date (specified in YYYY-MM-DD format) used for expiration change, denoting + when credits transferred (as part of a partial block expiration) should expire. + This date must be on or after the effective date of the credit block. """ amount: Optional[float] @@ -161,6 +215,9 @@ class AddExpirationChangeCreditLedgerEntryRequestParams(TypedDict, total=False): for noting corrections as a result of an incident, etc. """ + expiry_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """An ISO 8601 format date that identifies the origination credit block to expire""" + metadata: Optional[Dict[str, Optional[str]]] """User-specified key/value pairs for the resource. @@ -240,7 +297,7 @@ class AddAmendmentCreditLedgerEntryRequestParams(TypedDict, total=False): """ -LedgerCreateEntryParams = Union[ +LedgerCreateEntryParams: TypeAlias = Union[ AddIncrementCreditLedgerEntryRequestParams, AddDecrementCreditLedgerEntryRequestParams, AddExpirationChangeCreditLedgerEntryRequestParams, 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 0c287bbf..69ed1993 100644 --- a/src/orb/types/customers/credits/ledger_create_entry_response.py +++ b/src/orb/types/customers/credits/ledger_create_entry_response.py @@ -1,397 +1,28 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, Union, Optional -from datetime import datetime -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = [ - "LedgerCreateEntryResponse", - "IncrementLedgerEntry", - "IncrementLedgerEntryCreditBlock", - "IncrementLedgerEntryCustomer", - "DecrementLedgerEntry", - "DecrementLedgerEntryCreditBlock", - "DecrementLedgerEntryCustomer", - "ExpirationChangeLedgerEntry", - "ExpirationChangeLedgerEntryCreditBlock", - "ExpirationChangeLedgerEntryCustomer", - "CreditBlockExpiryLedgerEntry", - "CreditBlockExpiryLedgerEntryCreditBlock", - "CreditBlockExpiryLedgerEntryCustomer", - "VoidLedgerEntry", - "VoidLedgerEntryCreditBlock", - "VoidLedgerEntryCustomer", - "VoidInitiatedLedgerEntry", - "VoidInitiatedLedgerEntryCreditBlock", - "VoidInitiatedLedgerEntryCustomer", - "AmendmentLedgerEntry", - "AmendmentLedgerEntryCreditBlock", - "AmendmentLedgerEntryCustomer", -] - - -class IncrementLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class IncrementLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class IncrementLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: IncrementLedgerEntryCreditBlock - - currency: str - - customer: IncrementLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["increment"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - -class DecrementLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class DecrementLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class DecrementLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: DecrementLedgerEntryCreditBlock - - currency: str - - customer: DecrementLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["decrement"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - event_id: Optional[str] = None - - invoice_id: Optional[str] = None - - price_id: Optional[str] = None - - -class ExpirationChangeLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class ExpirationChangeLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class ExpirationChangeLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: ExpirationChangeLedgerEntryCreditBlock - - currency: str - - customer: ExpirationChangeLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["expiration_change"] - - ledger_sequence_number: int - - 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`. - """ - - new_block_expiry_date: datetime - - starting_balance: float - - -class CreditBlockExpiryLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class CreditBlockExpiryLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class CreditBlockExpiryLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: CreditBlockExpiryLedgerEntryCreditBlock - - currency: str - - customer: CreditBlockExpiryLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["credit_block_expiry"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - -class VoidLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class VoidLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class VoidLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: VoidLedgerEntryCreditBlock - - currency: str - - customer: VoidLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["void"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - void_amount: float - - void_reason: Optional[str] = None - - -class VoidInitiatedLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class VoidInitiatedLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class VoidInitiatedLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: VoidInitiatedLedgerEntryCreditBlock - - currency: str - - customer: VoidInitiatedLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["void_initiated"] - - ledger_sequence_number: int - - 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`. - """ - - new_block_expiry_date: datetime - - starting_balance: float - - void_amount: float - - void_reason: Optional[str] = None - - -class AmendmentLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class AmendmentLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class AmendmentLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: AmendmentLedgerEntryCreditBlock - - currency: str - - customer: AmendmentLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["amendment"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - -LedgerCreateEntryResponse = Union[ - IncrementLedgerEntry, - DecrementLedgerEntry, - ExpirationChangeLedgerEntry, - CreditBlockExpiryLedgerEntry, - VoidLedgerEntry, - VoidInitiatedLedgerEntry, - AmendmentLedgerEntry, +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ...._utils import PropertyInfo +from .void_ledger_entry import VoidLedgerEntry +from .amendment_ledger_entry import AmendmentLedgerEntry +from .decrement_ledger_entry import DecrementLedgerEntry +from .increment_ledger_entry import IncrementLedgerEntry +from .void_initiated_ledger_entry import VoidInitiatedLedgerEntry +from .expiration_change_ledger_entry import ExpirationChangeLedgerEntry +from .credit_block_expiry_ledger_entry import CreditBlockExpiryLedgerEntry + +__all__ = ["LedgerCreateEntryResponse"] + +LedgerCreateEntryResponse: TypeAlias = Annotated[ + Union[ + IncrementLedgerEntry, + DecrementLedgerEntry, + ExpirationChangeLedgerEntry, + CreditBlockExpiryLedgerEntry, + VoidLedgerEntry, + VoidInitiatedLedgerEntry, + AmendmentLedgerEntry, + ], + PropertyInfo(discriminator="entry_type"), ] 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 05e00a91..dd1a6df1 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 @@ -1,397 +1,28 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, Union, Optional -from datetime import datetime -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = [ - "LedgerListByExternalIDResponse", - "IncrementLedgerEntry", - "IncrementLedgerEntryCreditBlock", - "IncrementLedgerEntryCustomer", - "DecrementLedgerEntry", - "DecrementLedgerEntryCreditBlock", - "DecrementLedgerEntryCustomer", - "ExpirationChangeLedgerEntry", - "ExpirationChangeLedgerEntryCreditBlock", - "ExpirationChangeLedgerEntryCustomer", - "CreditBlockExpiryLedgerEntry", - "CreditBlockExpiryLedgerEntryCreditBlock", - "CreditBlockExpiryLedgerEntryCustomer", - "VoidLedgerEntry", - "VoidLedgerEntryCreditBlock", - "VoidLedgerEntryCustomer", - "VoidInitiatedLedgerEntry", - "VoidInitiatedLedgerEntryCreditBlock", - "VoidInitiatedLedgerEntryCustomer", - "AmendmentLedgerEntry", - "AmendmentLedgerEntryCreditBlock", - "AmendmentLedgerEntryCustomer", -] - - -class IncrementLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class IncrementLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class IncrementLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: IncrementLedgerEntryCreditBlock - - currency: str - - customer: IncrementLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["increment"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - -class DecrementLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class DecrementLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class DecrementLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: DecrementLedgerEntryCreditBlock - - currency: str - - customer: DecrementLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["decrement"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - event_id: Optional[str] = None - - invoice_id: Optional[str] = None - - price_id: Optional[str] = None - - -class ExpirationChangeLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class ExpirationChangeLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class ExpirationChangeLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: ExpirationChangeLedgerEntryCreditBlock - - currency: str - - customer: ExpirationChangeLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["expiration_change"] - - ledger_sequence_number: int - - 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`. - """ - - new_block_expiry_date: datetime - - starting_balance: float - - -class CreditBlockExpiryLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class CreditBlockExpiryLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class CreditBlockExpiryLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: CreditBlockExpiryLedgerEntryCreditBlock - - currency: str - - customer: CreditBlockExpiryLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["credit_block_expiry"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - -class VoidLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class VoidLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class VoidLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: VoidLedgerEntryCreditBlock - - currency: str - - customer: VoidLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["void"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - void_amount: float - - void_reason: Optional[str] = None - - -class VoidInitiatedLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class VoidInitiatedLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class VoidInitiatedLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: VoidInitiatedLedgerEntryCreditBlock - - currency: str - - customer: VoidInitiatedLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["void_initiated"] - - ledger_sequence_number: int - - 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`. - """ - - new_block_expiry_date: datetime - - starting_balance: float - - void_amount: float - - void_reason: Optional[str] = None - - -class AmendmentLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class AmendmentLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class AmendmentLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: AmendmentLedgerEntryCreditBlock - - currency: str - - customer: AmendmentLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["amendment"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - -LedgerListByExternalIDResponse = Union[ - IncrementLedgerEntry, - DecrementLedgerEntry, - ExpirationChangeLedgerEntry, - CreditBlockExpiryLedgerEntry, - VoidLedgerEntry, - VoidInitiatedLedgerEntry, - AmendmentLedgerEntry, +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ...._utils import PropertyInfo +from .void_ledger_entry import VoidLedgerEntry +from .amendment_ledger_entry import AmendmentLedgerEntry +from .decrement_ledger_entry import DecrementLedgerEntry +from .increment_ledger_entry import IncrementLedgerEntry +from .void_initiated_ledger_entry import VoidInitiatedLedgerEntry +from .expiration_change_ledger_entry import ExpirationChangeLedgerEntry +from .credit_block_expiry_ledger_entry import CreditBlockExpiryLedgerEntry + +__all__ = ["LedgerListByExternalIDResponse"] + +LedgerListByExternalIDResponse: TypeAlias = Annotated[ + Union[ + IncrementLedgerEntry, + DecrementLedgerEntry, + ExpirationChangeLedgerEntry, + CreditBlockExpiryLedgerEntry, + VoidLedgerEntry, + VoidInitiatedLedgerEntry, + AmendmentLedgerEntry, + ], + PropertyInfo(discriminator="entry_type"), ] diff --git a/src/orb/types/customers/credits/ledger_list_response.py b/src/orb/types/customers/credits/ledger_list_response.py index 0f2a5585..8cc43e8b 100644 --- a/src/orb/types/customers/credits/ledger_list_response.py +++ b/src/orb/types/customers/credits/ledger_list_response.py @@ -1,397 +1,28 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, Union, Optional -from datetime import datetime -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = [ - "LedgerListResponse", - "IncrementLedgerEntry", - "IncrementLedgerEntryCreditBlock", - "IncrementLedgerEntryCustomer", - "DecrementLedgerEntry", - "DecrementLedgerEntryCreditBlock", - "DecrementLedgerEntryCustomer", - "ExpirationChangeLedgerEntry", - "ExpirationChangeLedgerEntryCreditBlock", - "ExpirationChangeLedgerEntryCustomer", - "CreditBlockExpiryLedgerEntry", - "CreditBlockExpiryLedgerEntryCreditBlock", - "CreditBlockExpiryLedgerEntryCustomer", - "VoidLedgerEntry", - "VoidLedgerEntryCreditBlock", - "VoidLedgerEntryCustomer", - "VoidInitiatedLedgerEntry", - "VoidInitiatedLedgerEntryCreditBlock", - "VoidInitiatedLedgerEntryCustomer", - "AmendmentLedgerEntry", - "AmendmentLedgerEntryCreditBlock", - "AmendmentLedgerEntryCustomer", -] - - -class IncrementLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class IncrementLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class IncrementLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: IncrementLedgerEntryCreditBlock - - currency: str - - customer: IncrementLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["increment"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - -class DecrementLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class DecrementLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class DecrementLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: DecrementLedgerEntryCreditBlock - - currency: str - - customer: DecrementLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["decrement"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - event_id: Optional[str] = None - - invoice_id: Optional[str] = None - - price_id: Optional[str] = None - - -class ExpirationChangeLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class ExpirationChangeLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class ExpirationChangeLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: ExpirationChangeLedgerEntryCreditBlock - - currency: str - - customer: ExpirationChangeLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["expiration_change"] - - ledger_sequence_number: int - - 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`. - """ - - new_block_expiry_date: datetime - - starting_balance: float - - -class CreditBlockExpiryLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class CreditBlockExpiryLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class CreditBlockExpiryLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: CreditBlockExpiryLedgerEntryCreditBlock - - currency: str - - customer: CreditBlockExpiryLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["credit_block_expiry"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - -class VoidLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class VoidLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class VoidLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: VoidLedgerEntryCreditBlock - - currency: str - - customer: VoidLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["void"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - void_amount: float - - void_reason: Optional[str] = None - - -class VoidInitiatedLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class VoidInitiatedLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class VoidInitiatedLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: VoidInitiatedLedgerEntryCreditBlock - - currency: str - - customer: VoidInitiatedLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["void_initiated"] - - ledger_sequence_number: int - - 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`. - """ - - new_block_expiry_date: datetime - - starting_balance: float - - void_amount: float - - void_reason: Optional[str] = None - - -class AmendmentLedgerEntryCreditBlock(BaseModel): - id: str - - expiry_date: Optional[datetime] = None - - per_unit_cost_basis: Optional[str] = None - - -class AmendmentLedgerEntryCustomer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class AmendmentLedgerEntry(BaseModel): - id: str - - amount: float - - created_at: datetime - - credit_block: AmendmentLedgerEntryCreditBlock - - currency: str - - customer: AmendmentLedgerEntryCustomer - - description: Optional[str] = None - - ending_balance: float - - entry_status: Literal["committed", "pending"] - - entry_type: Literal["amendment"] - - ledger_sequence_number: int - - 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`. - """ - - starting_balance: float - - -LedgerListResponse = Union[ - IncrementLedgerEntry, - DecrementLedgerEntry, - ExpirationChangeLedgerEntry, - CreditBlockExpiryLedgerEntry, - VoidLedgerEntry, - VoidInitiatedLedgerEntry, - AmendmentLedgerEntry, +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ...._utils import PropertyInfo +from .void_ledger_entry import VoidLedgerEntry +from .amendment_ledger_entry import AmendmentLedgerEntry +from .decrement_ledger_entry import DecrementLedgerEntry +from .increment_ledger_entry import IncrementLedgerEntry +from .void_initiated_ledger_entry import VoidInitiatedLedgerEntry +from .expiration_change_ledger_entry import ExpirationChangeLedgerEntry +from .credit_block_expiry_ledger_entry import CreditBlockExpiryLedgerEntry + +__all__ = ["LedgerListResponse"] + +LedgerListResponse: TypeAlias = Annotated[ + Union[ + IncrementLedgerEntry, + DecrementLedgerEntry, + ExpirationChangeLedgerEntry, + CreditBlockExpiryLedgerEntry, + VoidLedgerEntry, + VoidInitiatedLedgerEntry, + AmendmentLedgerEntry, + ], + PropertyInfo(discriminator="entry_type"), ] diff --git a/src/orb/types/customers/credits/top_up_create_by_external_id_params.py b/src/orb/types/customers/credits/top_up_create_by_external_id_params.py index 5cb1f2fc..189d8c61 100644 --- a/src/orb/types/customers/credits/top_up_create_by_external_id_params.py +++ b/src/orb/types/customers/credits/top_up_create_by_external_id_params.py @@ -2,8 +2,11 @@ from __future__ import annotations -from typing import Optional -from typing_extensions import Literal, Required, TypedDict +from typing import Union, Optional +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ...._utils import PropertyInfo __all__ = ["TopUpCreateByExternalIDParams", "InvoiceSettings"] @@ -31,6 +34,13 @@ class TopUpCreateByExternalIDParams(TypedDict, total=False): If the balance is at or below this threshold, the top-up will be triggered. """ + active_from: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The date from which the top-up is active. + + If unspecified, the top-up is active immediately. This should not be more than + 10 days in the past. + """ + expires_after: Optional[int] """The number of days or months after which the top-up expires. @@ -42,6 +52,8 @@ class TopUpCreateByExternalIDParams(TypedDict, total=False): class InvoiceSettings(TypedDict, total=False): + """Settings for invoices generated by triggered top-ups.""" + auto_collection: Required[bool] """ Whether the credits purchase invoice should auto collect with the customer's @@ -57,3 +69,11 @@ class InvoiceSettings(TypedDict, total=False): memo: Optional[str] """An optional memo to display on the invoice.""" + + require_successful_payment: bool + """ + When true, credit blocks created by this top-up will require that the + corresponding invoice is paid before they are drawn down from. If any topup + block is pending payment, further automatic top-ups will be paused until the + invoice is paid or voided. + """ diff --git a/src/orb/types/customers/credits/top_up_create_by_external_id_response.py b/src/orb/types/customers/credits/top_up_create_by_external_id_response.py index 88d5c76a..dfe96773 100644 --- a/src/orb/types/customers/credits/top_up_create_by_external_id_response.py +++ b/src/orb/types/customers/credits/top_up_create_by_external_id_response.py @@ -4,26 +4,9 @@ from typing_extensions import Literal from ...._models import BaseModel +from .top_up_invoice_settings import TopUpInvoiceSettings -__all__ = ["TopUpCreateByExternalIDResponse", "InvoiceSettings"] - - -class InvoiceSettings(BaseModel): - auto_collection: bool - """ - Whether the credits purchase invoice should auto collect with the customer's - saved payment method. - """ - - net_terms: int - """ - The net terms determines the difference between the invoice date and the issue - date for the invoice. If you intend the invoice to be due on issue, set this - to 0. - """ - - memo: Optional[str] = None - """An optional memo to display on the invoice.""" +__all__ = ["TopUpCreateByExternalIDResponse"] class TopUpCreateByExternalIDResponse(BaseModel): @@ -39,7 +22,7 @@ class TopUpCreateByExternalIDResponse(BaseModel): currency. """ - invoice_settings: InvoiceSettings + invoice_settings: TopUpInvoiceSettings """Settings for invoices generated by triggered top-ups.""" per_unit_cost_basis: str diff --git a/src/orb/types/customers/credits/top_up_create_params.py b/src/orb/types/customers/credits/top_up_create_params.py index ed315746..7ffef30b 100644 --- a/src/orb/types/customers/credits/top_up_create_params.py +++ b/src/orb/types/customers/credits/top_up_create_params.py @@ -2,8 +2,11 @@ from __future__ import annotations -from typing import Optional -from typing_extensions import Literal, Required, TypedDict +from typing import Union, Optional +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ...._utils import PropertyInfo __all__ = ["TopUpCreateParams", "InvoiceSettings"] @@ -31,6 +34,13 @@ class TopUpCreateParams(TypedDict, total=False): If the balance is at or below this threshold, the top-up will be triggered. """ + active_from: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The date from which the top-up is active. + + If unspecified, the top-up is active immediately. This should not be more than + 10 days in the past. + """ + expires_after: Optional[int] """The number of days or months after which the top-up expires. @@ -42,6 +52,8 @@ class TopUpCreateParams(TypedDict, total=False): class InvoiceSettings(TypedDict, total=False): + """Settings for invoices generated by triggered top-ups.""" + auto_collection: Required[bool] """ Whether the credits purchase invoice should auto collect with the customer's @@ -57,3 +69,11 @@ class InvoiceSettings(TypedDict, total=False): memo: Optional[str] """An optional memo to display on the invoice.""" + + require_successful_payment: bool + """ + When true, credit blocks created by this top-up will require that the + corresponding invoice is paid before they are drawn down from. If any topup + block is pending payment, further automatic top-ups will be paused until the + invoice is paid or voided. + """ diff --git a/src/orb/types/customers/credits/top_up_create_response.py b/src/orb/types/customers/credits/top_up_create_response.py index d5c03f50..7cfee71a 100644 --- a/src/orb/types/customers/credits/top_up_create_response.py +++ b/src/orb/types/customers/credits/top_up_create_response.py @@ -4,26 +4,9 @@ from typing_extensions import Literal from ...._models import BaseModel +from .top_up_invoice_settings import TopUpInvoiceSettings -__all__ = ["TopUpCreateResponse", "InvoiceSettings"] - - -class InvoiceSettings(BaseModel): - auto_collection: bool - """ - Whether the credits purchase invoice should auto collect with the customer's - saved payment method. - """ - - net_terms: int - """ - The net terms determines the difference between the invoice date and the issue - date for the invoice. If you intend the invoice to be due on issue, set this - to 0. - """ - - memo: Optional[str] = None - """An optional memo to display on the invoice.""" +__all__ = ["TopUpCreateResponse"] class TopUpCreateResponse(BaseModel): @@ -39,7 +22,7 @@ class TopUpCreateResponse(BaseModel): currency. """ - invoice_settings: InvoiceSettings + invoice_settings: TopUpInvoiceSettings """Settings for invoices generated by triggered top-ups.""" per_unit_cost_basis: str diff --git a/src/orb/types/customers/credits/top_up_invoice_settings.py b/src/orb/types/customers/credits/top_up_invoice_settings.py new file mode 100644 index 00000000..d6446d32 --- /dev/null +++ b/src/orb/types/customers/credits/top_up_invoice_settings.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel + +__all__ = ["TopUpInvoiceSettings"] + + +class TopUpInvoiceSettings(BaseModel): + auto_collection: bool + """ + Whether the credits purchase invoice should auto collect with the customer's + saved payment method. + """ + + net_terms: int + """ + The net terms determines the difference between the invoice date and the issue + date for the invoice. If you intend the invoice to be due on issue, set this + to 0. + """ + + memo: Optional[str] = None + """An optional memo to display on the invoice.""" + + require_successful_payment: Optional[bool] = None + """ + When true, credit blocks created by this top-up will require that the + corresponding invoice is paid before they are drawn down from. If any topup + block is pending payment, further automatic top-ups will be paused until the + invoice is paid or voided. + """ diff --git a/src/orb/types/customers/credits/top_up_list_by_external_id_response.py b/src/orb/types/customers/credits/top_up_list_by_external_id_response.py index 7a911af6..4628cd40 100644 --- a/src/orb/types/customers/credits/top_up_list_by_external_id_response.py +++ b/src/orb/types/customers/credits/top_up_list_by_external_id_response.py @@ -4,26 +4,9 @@ from typing_extensions import Literal from ...._models import BaseModel +from .top_up_invoice_settings import TopUpInvoiceSettings -__all__ = ["TopUpListByExternalIDResponse", "InvoiceSettings"] - - -class InvoiceSettings(BaseModel): - auto_collection: bool - """ - Whether the credits purchase invoice should auto collect with the customer's - saved payment method. - """ - - net_terms: int - """ - The net terms determines the difference between the invoice date and the issue - date for the invoice. If you intend the invoice to be due on issue, set this - to 0. - """ - - memo: Optional[str] = None - """An optional memo to display on the invoice.""" +__all__ = ["TopUpListByExternalIDResponse"] class TopUpListByExternalIDResponse(BaseModel): @@ -39,7 +22,7 @@ class TopUpListByExternalIDResponse(BaseModel): currency. """ - invoice_settings: InvoiceSettings + invoice_settings: TopUpInvoiceSettings """Settings for invoices generated by triggered top-ups.""" per_unit_cost_basis: str diff --git a/src/orb/types/customers/credits/top_up_list_response.py b/src/orb/types/customers/credits/top_up_list_response.py index e3e824b4..9e186bb9 100644 --- a/src/orb/types/customers/credits/top_up_list_response.py +++ b/src/orb/types/customers/credits/top_up_list_response.py @@ -4,26 +4,9 @@ from typing_extensions import Literal from ...._models import BaseModel +from .top_up_invoice_settings import TopUpInvoiceSettings -__all__ = ["TopUpListResponse", "InvoiceSettings"] - - -class InvoiceSettings(BaseModel): - auto_collection: bool - """ - Whether the credits purchase invoice should auto collect with the customer's - saved payment method. - """ - - net_terms: int - """ - The net terms determines the difference between the invoice date and the issue - date for the invoice. If you intend the invoice to be due on issue, set this - to 0. - """ - - memo: Optional[str] = None - """An optional memo to display on the invoice.""" +__all__ = ["TopUpListResponse"] class TopUpListResponse(BaseModel): @@ -39,7 +22,7 @@ class TopUpListResponse(BaseModel): currency. """ - invoice_settings: InvoiceSettings + invoice_settings: TopUpInvoiceSettings """Settings for invoices generated by triggered top-ups.""" per_unit_cost_basis: str diff --git a/src/orb/types/customers/credits/void_initiated_ledger_entry.py b/src/orb/types/customers/credits/void_initiated_ledger_entry.py new file mode 100644 index 00000000..b5db1101 --- /dev/null +++ b/src/orb/types/customers/credits/void_initiated_ledger_entry.py @@ -0,0 +1,51 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel +from .affected_block import AffectedBlock +from ...shared.customer_minified import CustomerMinified + +__all__ = ["VoidInitiatedLedgerEntry"] + + +class VoidInitiatedLedgerEntry(BaseModel): + id: str + + amount: float + + created_at: datetime + + credit_block: AffectedBlock + + currency: str + + customer: CustomerMinified + + description: Optional[str] = None + + ending_balance: float + + entry_status: Literal["committed", "pending"] + + entry_type: Literal["void_initiated"] + + ledger_sequence_number: int + + 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`. + """ + + new_block_expiry_date: datetime + + starting_balance: float + + void_amount: float + + void_reason: Optional[str] = None diff --git a/src/orb/types/customers/credits/void_ledger_entry.py b/src/orb/types/customers/credits/void_ledger_entry.py new file mode 100644 index 00000000..6f96717b --- /dev/null +++ b/src/orb/types/customers/credits/void_ledger_entry.py @@ -0,0 +1,49 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel +from .affected_block import AffectedBlock +from ...shared.customer_minified import CustomerMinified + +__all__ = ["VoidLedgerEntry"] + + +class VoidLedgerEntry(BaseModel): + id: str + + amount: float + + created_at: datetime + + credit_block: AffectedBlock + + currency: str + + customer: CustomerMinified + + description: Optional[str] = None + + ending_balance: float + + entry_status: Literal["committed", "pending"] + + entry_type: Literal["void"] + + ledger_sequence_number: int + + 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`. + """ + + starting_balance: float + + void_amount: float + + void_reason: Optional[str] = None diff --git a/src/orb/types/customers/usage_update_by_external_id_params.py b/src/orb/types/customers/usage_update_by_external_id_params.py deleted file mode 100644 index 8458d6fd..00000000 --- a/src/orb/types/customers/usage_update_by_external_id_params.py +++ /dev/null @@ -1,53 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["UsageUpdateByExternalIDParams", "Event"] - - -class UsageUpdateByExternalIDParams(TypedDict, total=False): - events: Required[Iterable[Event]] - """Events to update""" - - timeframe_end: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """This bound is exclusive (i.e. events before this timestamp will be updated)""" - - timeframe_start: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """This bound is inclusive (i.e. - - events with this timestamp onward, inclusive will be updated) - """ - - -class Event(TypedDict, total=False): - event_name: Required[str] - """A name to meaningfully identify the action or event type.""" - - properties: Required[object] - """A dictionary of custom properties. - - Values in this dictionary must be numeric, boolean, or strings. Nested - dictionaries are disallowed. - """ - - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """An ISO 8601 format date with no timezone offset (i.e. - - UTC). This should represent the time that usage was recorded, and is - particularly important to attribute usage to a given billing period. - """ - - customer_id: Optional[str] - """The Orb Customer identifier""" - - external_customer_id: Optional[str] - """ - An alias for the Orb customer, whose mapping is specified when creating the - customer - """ diff --git a/src/orb/types/customers/usage_update_by_external_id_response.py b/src/orb/types/customers/usage_update_by_external_id_response.py deleted file mode 100644 index 62e93cfa..00000000 --- a/src/orb/types/customers/usage_update_by_external_id_response.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List - -from ..._models import BaseModel - -__all__ = ["UsageUpdateByExternalIDResponse"] - - -class UsageUpdateByExternalIDResponse(BaseModel): - duplicate: List[str] - """ - An array of strings, corresponding to idempotency_key's marked as duplicates - (previously ingested) - """ - - ingested: List[str] - """ - An array of strings, corresponding to idempotency_key's which were successfully - ingested. - """ diff --git a/src/orb/types/customers/usage_update_params.py b/src/orb/types/customers/usage_update_params.py deleted file mode 100644 index b664e189..00000000 --- a/src/orb/types/customers/usage_update_params.py +++ /dev/null @@ -1,53 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["UsageUpdateParams", "Event"] - - -class UsageUpdateParams(TypedDict, total=False): - events: Required[Iterable[Event]] - """Events to update""" - - timeframe_end: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """This bound is exclusive (i.e. events before this timestamp will be updated)""" - - timeframe_start: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """This bound is inclusive (i.e. - - events with this timestamp onward, inclusive will be updated) - """ - - -class Event(TypedDict, total=False): - event_name: Required[str] - """A name to meaningfully identify the action or event type.""" - - properties: Required[object] - """A dictionary of custom properties. - - Values in this dictionary must be numeric, boolean, or strings. Nested - dictionaries are disallowed. - """ - - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """An ISO 8601 format date with no timezone offset (i.e. - - UTC). This should represent the time that usage was recorded, and is - particularly important to attribute usage to a given billing period. - """ - - customer_id: Optional[str] - """The Orb Customer identifier""" - - external_customer_id: Optional[str] - """ - An alias for the Orb customer, whose mapping is specified when creating the - customer - """ diff --git a/src/orb/types/customers/usage_update_response.py b/src/orb/types/customers/usage_update_response.py deleted file mode 100644 index fdc2f023..00000000 --- a/src/orb/types/customers/usage_update_response.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List - -from ..._models import BaseModel - -__all__ = ["UsageUpdateResponse"] - - -class UsageUpdateResponse(BaseModel): - duplicate: List[str] - """ - An array of strings, corresponding to idempotency_key's marked as duplicates - (previously ingested) - """ - - ingested: List[str] - """ - An array of strings, corresponding to idempotency_key's which were successfully - ingested. - """ diff --git a/src/orb/types/dimensional_price_group.py b/src/orb/types/dimensional_price_group.py new file mode 100644 index 00000000..368f4817 --- /dev/null +++ b/src/orb/types/dimensional_price_group.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from .._models import BaseModel + +__all__ = ["DimensionalPriceGroup"] + + +class DimensionalPriceGroup(BaseModel): + """ + A dimensional price group is used to partition the result of a billable metric by a set of dimensions. Prices in a + price group must specify the partition used to derive their usage. + """ + + id: str + + billable_metric_id: str + """The billable metric associated with this dimensional price group. + + All prices associated with this dimensional price group will be computed using + this billable metric. + """ + + dimensions: List[str] + """The dimensions that this dimensional price group is defined over""" + + external_dimensional_price_group_id: Optional[str] = None + """An alias for the dimensional price group""" + + 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`. + """ + + name: str + """The name of the dimensional price group""" diff --git a/src/orb/types/dimensional_price_group_create_params.py b/src/orb/types/dimensional_price_group_create_params.py new file mode 100644 index 00000000..d1780014 --- /dev/null +++ b/src/orb/types/dimensional_price_group_create_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Required, TypedDict + +from .._types import SequenceNotStr + +__all__ = ["DimensionalPriceGroupCreateParams"] + + +class DimensionalPriceGroupCreateParams(TypedDict, total=False): + billable_metric_id: Required[str] + + dimensions: Required[SequenceNotStr[str]] + """The set of keys (in order) used to disambiguate prices in the group.""" + + name: Required[str] + + external_dimensional_price_group_id: Optional[str] + + 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`. + """ diff --git a/src/orb/types/dimensional_price_group_list_params.py b/src/orb/types/dimensional_price_group_list_params.py new file mode 100644 index 00000000..f385535e --- /dev/null +++ b/src/orb/types/dimensional_price_group_list_params.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +__all__ = ["DimensionalPriceGroupListParams"] + + +class DimensionalPriceGroupListParams(TypedDict, total=False): + 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.""" diff --git a/src/orb/types/dimensional_price_group_update_params.py b/src/orb/types/dimensional_price_group_update_params.py new file mode 100644 index 00000000..d6f02491 --- /dev/null +++ b/src/orb/types/dimensional_price_group_update_params.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import TypedDict + +__all__ = ["DimensionalPriceGroupUpdateParams"] + + +class DimensionalPriceGroupUpdateParams(TypedDict, total=False): + external_dimensional_price_group_id: Optional[str] + """ + An optional user-defined ID for this dimensional price group resource, used + throughout the system as an alias for this dimensional price group. Use this + field to identify a dimensional price group by an existing identifier in your + system. + """ + + 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`. + """ diff --git a/src/orb/types/dimensional_price_groups/__init__.py b/src/orb/types/dimensional_price_groups/__init__.py new file mode 100644 index 00000000..af893956 --- /dev/null +++ b/src/orb/types/dimensional_price_groups/__init__.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .dimensional_price_groups import DimensionalPriceGroups as DimensionalPriceGroups +from .external_dimensional_price_group_id_update_params import ( + ExternalDimensionalPriceGroupIDUpdateParams as ExternalDimensionalPriceGroupIDUpdateParams, +) diff --git a/src/orb/types/dimensional_price_groups/dimensional_price_groups.py b/src/orb/types/dimensional_price_groups/dimensional_price_groups.py new file mode 100644 index 00000000..78893603 --- /dev/null +++ b/src/orb/types/dimensional_price_groups/dimensional_price_groups.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from ..dimensional_price_group import DimensionalPriceGroup +from ..shared.pagination_metadata import PaginationMetadata + +__all__ = ["DimensionalPriceGroups"] + + +class DimensionalPriceGroups(BaseModel): + data: List[DimensionalPriceGroup] + + pagination_metadata: PaginationMetadata diff --git a/src/orb/types/dimensional_price_groups/external_dimensional_price_group_id_update_params.py b/src/orb/types/dimensional_price_groups/external_dimensional_price_group_id_update_params.py new file mode 100644 index 00000000..96fb619b --- /dev/null +++ b/src/orb/types/dimensional_price_groups/external_dimensional_price_group_id_update_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["ExternalDimensionalPriceGroupIDUpdateParams"] + + +class ExternalDimensionalPriceGroupIDUpdateParams(TypedDict, total=False): + body_external_dimensional_price_group_id: Annotated[ + Optional[str], PropertyInfo(alias="external_dimensional_price_group_id") + ] + """ + An optional user-defined ID for this dimensional price group resource, used + throughout the system as an alias for this dimensional price group. Use this + field to identify a dimensional price group by an existing identifier in your + system. + """ + + 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`. + """ diff --git a/src/orb/types/discount_override_param.py b/src/orb/types/discount_override_param.py new file mode 100644 index 00000000..d9aed916 --- /dev/null +++ b/src/orb/types/discount_override_param.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 Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["DiscountOverrideParam"] + + +class DiscountOverrideParam(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 + """ diff --git a/src/orb/types/beta/evaluate_price_group.py b/src/orb/types/evaluate_price_group.py similarity index 93% rename from src/orb/types/beta/evaluate_price_group.py rename to src/orb/types/evaluate_price_group.py index b1cffe49..2a6af81a 100644 --- a/src/orb/types/beta/evaluate_price_group.py +++ b/src/orb/types/evaluate_price_group.py @@ -2,7 +2,7 @@ from typing import List, Union -from ..._models import BaseModel +from .._models import BaseModel __all__ = ["EvaluatePriceGroup"] diff --git a/src/orb/types/event_ingest_params.py b/src/orb/types/event_ingest_params.py index 505fbfe6..ec641062 100644 --- a/src/orb/types/event_ingest_params.py +++ b/src/orb/types/event_ingest_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from datetime import datetime from typing_extensions import Required, Annotated, TypedDict @@ -21,7 +21,10 @@ class EventIngestParams(TypedDict, total=False): """ debug: bool - """Flag to enable additional debug information in the endpoint response""" + """ + Pending Deprecation: Flag to enable additional debug information in the endpoint + response + """ class Event(TypedDict, total=False): @@ -35,7 +38,7 @@ class Event(TypedDict, total=False): for safe request retries. """ - properties: Required[object] + properties: Required[Dict[str, object]] """A dictionary of custom properties. Values in this dictionary must be numeric, boolean, or strings. Nested diff --git a/src/orb/types/event_ingest_response.py b/src/orb/types/event_ingest_response.py index 933e18c8..92fcf7d3 100644 --- a/src/orb/types/event_ingest_response.py +++ b/src/orb/types/event_ingest_response.py @@ -19,6 +19,10 @@ class ValidationFailed(BaseModel): class Debug(BaseModel): + """ + Optional debug information (only present when debug=true is passed to the endpoint). Contains ingested and duplicate event idempotency keys. + """ + duplicate: List[str] ingested: List[str] diff --git a/src/orb/types/event_search_params.py b/src/orb/types/event_search_params.py index e422ae4f..a69e92ee 100644 --- a/src/orb/types/event_search_params.py +++ b/src/orb/types/event_search_params.py @@ -2,17 +2,18 @@ from __future__ import annotations -from typing import List, Union +from typing import Union from datetime import datetime from typing_extensions import Required, Annotated, TypedDict +from .._types import SequenceNotStr from .._utils import PropertyInfo __all__ = ["EventSearchParams"] class EventSearchParams(TypedDict, total=False): - event_ids: Required[List[str]] + event_ids: Required[SequenceNotStr[str]] """This is an explicit array of IDs to filter by. Note that an event's ID is the idempotency_key that was originally used for diff --git a/src/orb/types/event_search_response.py b/src/orb/types/event_search_response.py index ba96bc6e..9c252c48 100644 --- a/src/orb/types/event_search_response.py +++ b/src/orb/types/event_search_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional +from typing import Dict, List, Optional from datetime import datetime from .._models import BaseModel @@ -9,6 +9,12 @@ class Data(BaseModel): + """ + The [Event](/core-concepts#event) resource represents a usage event that has been created for a + customer. Events are the core of Orb's usage-based billing model, and are used to calculate the usage charges for + a given billing period. + """ + id: str """A unique value, generated by the client, that is used to de-duplicate events. @@ -19,6 +25,9 @@ class Data(BaseModel): customer_id: Optional[str] = None """The Orb Customer identifier""" + deprecated: bool + """A boolean indicating whether the event is currently deprecated.""" + event_name: str """A name to meaningfully identify the action or event type.""" @@ -28,7 +37,7 @@ class Data(BaseModel): customer """ - properties: object + properties: Dict[str, object] """A dictionary of custom properties. Values in this dictionary must be numeric, boolean, or strings. Nested diff --git a/src/orb/types/event_update_params.py b/src/orb/types/event_update_params.py index 3de8f966..934caa54 100644 --- a/src/orb/types/event_update_params.py +++ b/src/orb/types/event_update_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union, Optional +from typing import Dict, Union, Optional from datetime import datetime from typing_extensions import Required, Annotated, TypedDict @@ -15,7 +15,7 @@ class EventUpdateParams(TypedDict, total=False): event_name: Required[str] """A name to meaningfully identify the action or event type.""" - properties: Required[object] + properties: Required[Dict[str, object]] """A dictionary of custom properties. Values in this dictionary must be numeric, boolean, or strings. Nested 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 fae3016e..79725b60 100644 --- a/src/orb/types/events/backfill_close_response.py +++ b/src/orb/types/events/backfill_close_response.py @@ -10,6 +10,10 @@ class BackfillCloseResponse(BaseModel): + """ + A backfill represents an update to historical usage data, adding or replacing events in a timeframe. + """ + id: str close_time: Optional[datetime] = None @@ -21,9 +25,19 @@ 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 scoped to all customers. + """ - If null, this backfill is not scoped to a single customer. + events_ingested: int + """The number of events ingested in this backfill.""" + + replace_existing_events: bool + """ + If `true`, existing events in the backfill's timeframe will be replaced with the + newly ingested events associated with the backfill. If `false`, newly ingested + events will be added to the existing events. """ reverted_at: Optional[datetime] = None @@ -35,3 +49,10 @@ class BackfillCloseResponse(BaseModel): timeframe_end: datetime timeframe_start: datetime + + deprecation_filter: Optional[str] = None + """ + A boolean + [computed property](/extensibility/advanced-metrics#computed-properties) used to + filter the set of events to deprecate + """ diff --git a/src/orb/types/events/backfill_create_params.py b/src/orb/types/events/backfill_create_params.py index 1cd1c5b7..2ba0fe88 100644 --- a/src/orb/types/events/backfill_create_params.py +++ b/src/orb/types/events/backfill_create_params.py @@ -13,10 +13,18 @@ class BackfillCreateParams(TypedDict, total=False): timeframe_end: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """The (exclusive) end of the usage timeframe affected by this backfill.""" + """The (exclusive) end of the usage timeframe affected by this backfill. + + By default, Orb allows backfills up to 31 days in duration at a time. Reach out + to discuss extending this limit and your use case. + """ timeframe_start: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """The (inclusive) start of the usage timeframe affected by this backfill.""" + """The (inclusive) start of the usage timeframe affected by this backfill. + + By default, Orb allows backfills up to 31 days in duration at a time. Reach out + to discuss extending this limit and your use case. + """ close_time: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] """The time at which no more events will be accepted for this backfill. @@ -27,10 +35,23 @@ 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] + """ + A boolean + [computed property](/extensibility/advanced-metrics#computed-properties) used to + filter the set of events to deprecate + """ 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 8fc43b31..0f74914f 100644 --- a/src/orb/types/events/backfill_create_response.py +++ b/src/orb/types/events/backfill_create_response.py @@ -10,6 +10,10 @@ class BackfillCreateResponse(BaseModel): + """ + A backfill represents an update to historical usage data, adding or replacing events in a timeframe. + """ + id: str close_time: Optional[datetime] = None @@ -21,9 +25,19 @@ 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 scoped to all customers. + """ - If null, this backfill is not scoped to a single customer. + events_ingested: int + """The number of events ingested in this backfill.""" + + replace_existing_events: bool + """ + If `true`, existing events in the backfill's timeframe will be replaced with the + newly ingested events associated with the backfill. If `false`, newly ingested + events will be added to the existing events. """ reverted_at: Optional[datetime] = None @@ -35,3 +49,10 @@ class BackfillCreateResponse(BaseModel): timeframe_end: datetime timeframe_start: datetime + + deprecation_filter: Optional[str] = None + """ + A boolean + [computed property](/extensibility/advanced-metrics#computed-properties) used to + filter the set of events to deprecate + """ diff --git a/src/orb/types/events/backfill_fetch_response.py b/src/orb/types/events/backfill_fetch_response.py index 230d4d2c..182bc201 100644 --- a/src/orb/types/events/backfill_fetch_response.py +++ b/src/orb/types/events/backfill_fetch_response.py @@ -10,6 +10,10 @@ class BackfillFetchResponse(BaseModel): + """ + A backfill represents an update to historical usage data, adding or replacing events in a timeframe. + """ + id: str close_time: Optional[datetime] = None @@ -21,9 +25,19 @@ 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 scoped to all customers. + """ - If null, this backfill is not scoped to a single customer. + events_ingested: int + """The number of events ingested in this backfill.""" + + replace_existing_events: bool + """ + If `true`, existing events in the backfill's timeframe will be replaced with the + newly ingested events associated with the backfill. If `false`, newly ingested + events will be added to the existing events. """ reverted_at: Optional[datetime] = None @@ -35,3 +49,10 @@ class BackfillFetchResponse(BaseModel): timeframe_end: datetime timeframe_start: datetime + + deprecation_filter: Optional[str] = None + """ + A boolean + [computed property](/extensibility/advanced-metrics#computed-properties) used to + filter the set of events to deprecate + """ diff --git a/src/orb/types/events/backfill_list_response.py b/src/orb/types/events/backfill_list_response.py index d41dbc5d..2db0a724 100644 --- a/src/orb/types/events/backfill_list_response.py +++ b/src/orb/types/events/backfill_list_response.py @@ -10,6 +10,10 @@ class BackfillListResponse(BaseModel): + """ + A backfill represents an update to historical usage data, adding or replacing events in a timeframe. + """ + id: str close_time: Optional[datetime] = None @@ -21,9 +25,19 @@ 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 scoped to all customers. + """ - If null, this backfill is not scoped to a single customer. + events_ingested: int + """The number of events ingested in this backfill.""" + + replace_existing_events: bool + """ + If `true`, existing events in the backfill's timeframe will be replaced with the + newly ingested events associated with the backfill. If `false`, newly ingested + events will be added to the existing events. """ reverted_at: Optional[datetime] = None @@ -35,3 +49,10 @@ class BackfillListResponse(BaseModel): timeframe_end: datetime timeframe_start: datetime + + deprecation_filter: Optional[str] = None + """ + A boolean + [computed property](/extensibility/advanced-metrics#computed-properties) used to + filter the set of events to deprecate + """ diff --git a/src/orb/types/events/backfill_revert_response.py b/src/orb/types/events/backfill_revert_response.py index 33e091c9..949ac1b2 100644 --- a/src/orb/types/events/backfill_revert_response.py +++ b/src/orb/types/events/backfill_revert_response.py @@ -10,6 +10,10 @@ class BackfillRevertResponse(BaseModel): + """ + A backfill represents an update to historical usage data, adding or replacing events in a timeframe. + """ + id: str close_time: Optional[datetime] = None @@ -21,9 +25,19 @@ 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 scoped to all customers. + """ - If null, this backfill is not scoped to a single customer. + events_ingested: int + """The number of events ingested in this backfill.""" + + replace_existing_events: bool + """ + If `true`, existing events in the backfill's timeframe will be replaced with the + newly ingested events associated with the backfill. If `false`, newly ingested + events will be added to the existing events. """ reverted_at: Optional[datetime] = None @@ -35,3 +49,10 @@ class BackfillRevertResponse(BaseModel): timeframe_end: datetime timeframe_start: datetime + + deprecation_filter: Optional[str] = None + """ + A boolean + [computed property](/extensibility/advanced-metrics#computed-properties) used to + filter the set of events to deprecate + """ diff --git a/src/orb/types/events/event_volumes.py b/src/orb/types/events/event_volumes.py new file mode 100644 index 00000000..f9e84b32 --- /dev/null +++ b/src/orb/types/events/event_volumes.py @@ -0,0 +1,27 @@ +# 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): + """An EventVolume contains the event volume ingested in an hourly window. + + The timestamp used + for the aggregation is the `timestamp` datetime field on events. + """ + + 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 deleted file mode 100644 index 7e624228..00000000 --- a/src/orb/types/invoice.py +++ /dev/null @@ -1,956 +0,0 @@ -# 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 - -from .price import Price -from .shared import Discount -from .._models import BaseModel - -__all__ = [ - "Invoice", - "AutoCollection", - "BillingAddress", - "CreditNote", - "Customer", - "CustomerBalanceTransaction", - "CustomerBalanceTransactionCreditNote", - "CustomerBalanceTransactionInvoice", - "CustomerTaxID", - "LineItem", - "LineItemMaximum", - "LineItemMinimum", - "LineItemSubLineItem", - "LineItemSubLineItemMatrixSubLineItem", - "LineItemSubLineItemMatrixSubLineItemGrouping", - "LineItemSubLineItemMatrixSubLineItemMatrixConfig", - "LineItemSubLineItemTierSubLineItem", - "LineItemSubLineItemTierSubLineItemGrouping", - "LineItemSubLineItemTierSubLineItemTierConfig", - "LineItemSubLineItemOtherSubLineItem", - "LineItemSubLineItemOtherSubLineItemGrouping", - "LineItemTaxAmount", - "Maximum", - "Minimum", - "ShippingAddress", - "Subscription", -] - - -class AutoCollection(BaseModel): - enabled: Optional[bool] = None - """True only if auto-collection is enabled for this invoice.""" - - next_attempt_at: Optional[datetime] = None - """ - If the invoice is scheduled for auto-collection, this field will reflect when - the next attempt will occur. If dunning has been exhausted, or auto-collection - is not enabled for this invoice, this field will be `null`. - """ - - previously_attempted_at: Optional[datetime] = None - """ - If Orb has ever attempted payment auto-collection for this invoice, this field - will reflect when that attempt occurred. In conjunction with `next_attempt_at`, - this can be used to tell whether the invoice is currently in dunning (that is, - `previously_attempted_at` is non-null, and `next_attempt_time` is non-null), or - if dunning has been exhausted (`previously_attempted_at` is non-null, but - `next_attempt_time` is null). - """ - - -class BillingAddress(BaseModel): - city: Optional[str] = None - - country: Optional[str] = None - - line1: Optional[str] = None - - line2: Optional[str] = None - - postal_code: Optional[str] = None - - state: Optional[str] = None - - -class CreditNote(BaseModel): - id: str - - credit_note_number: str - - memo: Optional[str] = None - """An optional memo supplied on the credit note.""" - - reason: str - - total: str - - type: str - - voided_at: Optional[datetime] = None - """ - If the credit note has a status of `void`, this gives a timestamp when the - credit note was voided. - """ - - -class Customer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class CustomerBalanceTransactionCreditNote(BaseModel): - id: str - """The id of the Credit note""" - - -class CustomerBalanceTransactionInvoice(BaseModel): - id: str - """The Invoice id""" - - -class CustomerBalanceTransaction(BaseModel): - id: str - """A unique id for this transaction.""" - - action: Literal[ - "applied_to_invoice", - "manual_adjustment", - "prorated_refund", - "revert_prorated_refund", - "return_from_voiding", - "credit_note_applied", - "credit_note_voided", - "overpayment_refund", - ] - - amount: str - """The value of the amount changed in the transaction.""" - - created_at: datetime - """The creation time of this transaction.""" - - credit_note: Optional[CustomerBalanceTransactionCreditNote] = None - - description: Optional[str] = None - """An optional description provided for manual customer balance adjustments.""" - - ending_balance: str - """ - The new value of the customer's balance prior to the transaction, in the - customer's currency. - """ - - invoice: Optional[CustomerBalanceTransactionInvoice] = None - - starting_balance: str - """ - The original value of the customer's balance prior to the transaction, in the - customer's currency. - """ - - type: Literal["increment", "decrement"] - - -class CustomerTaxID(BaseModel): - country: Literal[ - "AD", - "AE", - "AT", - "AU", - "BE", - "BG", - "BR", - "CA", - "CH", - "CL", - "CY", - "CZ", - "DE", - "DK", - "EE", - "EG", - "ES", - "EU", - "FI", - "FR", - "GB", - "GE", - "GR", - "HK", - "HR", - "HU", - "ID", - "IE", - "IL", - "IN", - "IS", - "IT", - "JP", - "KE", - "KR", - "LI", - "LT", - "LU", - "LV", - "MT", - "MX", - "MY", - "NL", - "NO", - "NZ", - "PH", - "PL", - "PT", - "RO", - "RU", - "SA", - "SE", - "SG", - "SI", - "SK", - "TH", - "TR", - "TW", - "UA", - "US", - "ZA", - ] - - type: Literal[ - "ad_nrt", - "ae_trn", - "eu_vat", - "au_abn", - "au_arn", - "bg_uic", - "br_cnpj", - "br_cpf", - "ca_bn", - "ca_gst_hst", - "ca_pst_bc", - "ca_pst_mb", - "ca_pst_sk", - "ca_qst", - "ch_vat", - "cl_tin", - "eg_tin", - "es_cif", - "eu_oss_vat", - "gb_vat", - "ge_vat", - "hk_br", - "hu_tin", - "id_npwp", - "il_vat", - "in_gst", - "is_vat", - "jp_cn", - "jp_rn", - "jp_trn", - "ke_pin", - "kr_brn", - "li_uid", - "mx_rfc", - "my_frp", - "my_itn", - "my_sst", - "no_vat", - "nz_gst", - "ph_tin", - "ru_inn", - "ru_kpp", - "sa_vat", - "sg_gst", - "sg_uen", - "si_tin", - "th_vat", - "tr_tin", - "tw_vat", - "ua_vat", - "us_ein", - "za_vat", - ] - - value: str - - -class LineItemMaximum(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 LineItemMinimum(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 LineItemSubLineItemMatrixSubLineItemGrouping(BaseModel): - key: str - - value: Optional[str] = None - """No value indicates the default group""" - - -class LineItemSubLineItemMatrixSubLineItemMatrixConfig(BaseModel): - dimension_values: List[Optional[str]] - """The ordered dimension values for this line item.""" - - -class LineItemSubLineItemMatrixSubLineItem(BaseModel): - amount: str - """The total amount for this sub line item.""" - - grouping: Optional[LineItemSubLineItemMatrixSubLineItemGrouping] = None - - matrix_config: LineItemSubLineItemMatrixSubLineItemMatrixConfig - - name: str - - quantity: float - - type: Literal["matrix"] - - -class LineItemSubLineItemTierSubLineItemGrouping(BaseModel): - key: str - - value: Optional[str] = None - """No value indicates the default group""" - - -class LineItemSubLineItemTierSubLineItemTierConfig(BaseModel): - first_unit: float - - last_unit: Optional[float] = None - - unit_amount: str - - -class LineItemSubLineItemTierSubLineItem(BaseModel): - amount: str - """The total amount for this sub line item.""" - - grouping: Optional[LineItemSubLineItemTierSubLineItemGrouping] = None - - name: str - - quantity: float - - tier_config: LineItemSubLineItemTierSubLineItemTierConfig - - type: Literal["tier"] - - -class LineItemSubLineItemOtherSubLineItemGrouping(BaseModel): - key: str - - value: Optional[str] = None - """No value indicates the default group""" - - -class LineItemSubLineItemOtherSubLineItem(BaseModel): - amount: str - """The total amount for this sub line item.""" - - grouping: Optional[LineItemSubLineItemOtherSubLineItemGrouping] = None - - name: str - - quantity: float - - type: Literal["'null'"] - - -LineItemSubLineItem = Union[ - LineItemSubLineItemMatrixSubLineItem, LineItemSubLineItemTierSubLineItem, LineItemSubLineItemOtherSubLineItem -] - - -class LineItemTaxAmount(BaseModel): - amount: str - """The amount of additional tax incurred by this tax rate.""" - - tax_rate_description: str - """The human-readable description of the applied tax rate.""" - - tax_rate_percentage: Optional[str] = None - """The tax rate percentage, out of 100.""" - - -class LineItem(BaseModel): - id: str - """A unique ID for this line item.""" - - amount: str - """The final amount after any discounts or minimums.""" - - discount: Optional[Discount] = None - - end_date: datetime - """The end date of the range of time applied for this line item's price.""" - - grouping: Optional[str] = None - """ - [DEPRECATED] For configured prices that are split by a grouping key, this will - be populated with the key and a value. The `amount` and `subtotal` will be the - values for this particular grouping. - """ - - maximum: Optional[LineItemMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[LineItemMinimum] = None - - minimum_amount: Optional[str] = None - - name: str - """The name of the price associated with this line item.""" - - price: Optional[Price] = None - """ - 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 - ... - } - ``` - """ - - quantity: float - - start_date: datetime - """The start date of the range of time applied for this line item's price.""" - - sub_line_items: List[LineItemSubLineItem] - """ - For complex pricing structures, the line item can be broken down further in - `sub_line_items`. - """ - - subtotal: str - """The line amount before any line item-specific discounts or minimums.""" - - tax_amounts: List[LineItemTaxAmount] - """An array of tax rates and their incurred tax amounts. - - Empty if no tax integration is configured. - """ - - -class Maximum(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 Minimum(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 ShippingAddress(BaseModel): - city: Optional[str] = None - - country: Optional[str] = None - - line1: Optional[str] = None - - line2: Optional[str] = None - - postal_code: Optional[str] = None - - state: Optional[str] = None - - -class Subscription(BaseModel): - id: str - - -class Invoice(BaseModel): - id: str - - amount_due: str - """ - This is the final amount required to be charged to the customer and reflects the - application of the customer balance to the `total` of the invoice. - """ - - auto_collection: AutoCollection - - billing_address: Optional[BillingAddress] = None - - created_at: datetime - """The creation time of the resource in Orb.""" - - credit_notes: List[CreditNote] - """A list of credit notes associated with the invoice""" - - currency: str - """An ISO 4217 currency string or `credits`""" - - customer: Customer - - customer_balance_transactions: List[CustomerBalanceTransaction] - - customer_tax_id: Optional[CustomerTaxID] = None - """ - Tax IDs are commonly required to be displayed on customer invoices, which are - added to the headers of invoices. - - ### Supported Tax ID Countries and Types - - | Country | Type | Description | - | -------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | - | Andorra | `ad_nrt` | Andorran NRT number | - | Australia | `au_abn` | Australian Business Number (AU ABN) | - | Australia | `au_arn` | Australian Taxation Office Reference Number | - | Austria | `eu_vat` | European VAT number | - | Belgium | `eu_vat` | European VAT number | - | Brazil | `br_cnpj` | Brazilian CNPJ number | - | Brazil | `br_cpf` | Brazilian CPF number | - | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | - | Bulgaria | `eu_vat` | European VAT number | - | Canada | `ca_bn` | Canadian BN | - | Canada | `ca_gst_hst` | Canadian GST/HST number | - | Canada | `ca_pst_bc` | Canadian PST number (British Columbia) | - | Canada | `ca_pst_mb` | Canadian PST number (Manitoba) | - | Canada | `ca_pst_sk` | Canadian PST number (Saskatchewan) | - | Canada | `ca_qst` | Canadian QST number (Québec) | - | Chile | `cl_tin` | Chilean TIN | - | Croatia | `eu_vat` | European VAT number | - | Cyprus | `eu_vat` | European VAT number | - | Czech Republic | `eu_vat` | European VAT number | - | Denmark | `eu_vat` | European VAT number | - | Egypt | `eg_tin` | Egyptian Tax Identification Number | - | Estonia | `eu_vat` | European VAT number | - | EU | `eu_oss_vat` | European One Stop Shop VAT number for non-Union scheme | - | Finland | `eu_vat` | European VAT number | - | France | `eu_vat` | European VAT number | - | Georgia | `ge_vat` | Georgian VAT | - | Germany | `eu_vat` | European VAT number | - | Greece | `eu_vat` | European VAT number | - | Hong Kong | `hk_br` | Hong Kong BR number | - | Hungary | `eu_vat` | European VAT number | - | Hungary | `hu_tin` | Hungary tax number (adószám) | - | Iceland | `is_vat` | Icelandic VAT | - | India | `in_gst` | Indian GST number | - | Indonesia | `id_npwp` | Indonesian NPWP number | - | Ireland | `eu_vat` | European VAT number | - | Israel | `il_vat` | Israel VAT | - | Italy | `eu_vat` | European VAT number | - | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | - | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | - | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | - | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | - | Latvia | `eu_vat` | European VAT number | - | Liechtenstein | `li_uid` | Liechtensteinian UID number | - | Lithuania | `eu_vat` | European VAT number | - | Luxembourg | `eu_vat` | European VAT number | - | Malaysia | `my_frp` | Malaysian FRP number | - | Malaysia | `my_itn` | Malaysian ITN | - | Malaysia | `my_sst` | Malaysian SST number | - | Malta | `eu_vat ` | European VAT number | - | Mexico | `mx_rfc` | Mexican RFC number | - | Netherlands | `eu_vat` | European VAT number | - | New Zealand | `nz_gst` | New Zealand GST number | - | Norway | `no_vat` | Norwegian VAT number | - | Philippines | `ph_tin ` | Philippines Tax Identification Number | - | Poland | `eu_vat` | European VAT number | - | Portugal | `eu_vat` | European VAT number | - | Romania | `eu_vat` | European VAT number | - | Russia | `ru_inn` | Russian INN | - | Russia | `ru_kpp` | Russian KPP | - | Saudi Arabia | `sg_gst` | Singaporean GST | - | Singapore | `sg_uen` | Singaporean UEN | - | Slovakia | `eu_vat` | European VAT number | - | Slovenia | `eu_vat` | European VAT number | - | Slovenia | `si_tin` | Slovenia tax number (davčna številka) | - | South Africa | `za_vat` | South African VAT number | - | South Korea | `kr_brn` | Korean BRN | - | Spain | `es_cif` | Spanish NIF number (previously Spanish CIF number) | - | Spain | `eu_vat` | European VAT number | - | Sweden | `eu_vat` | European VAT number | - | Switzerland | `ch_vat` | Switzerland VAT number | - | Taiwan | `tw_vat` | Taiwanese VAT | - | Thailand | `th_vat` | Thai VAT | - | Turkey | `tr_tin` | Turkish Tax Identification Number | - | Ukraine | `ua_vat` | Ukrainian VAT | - | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | - | United Kingdom | `eu_vat` | Northern Ireland VAT number | - | United Kingdom | `gb_vat` | United Kingdom VAT number | - | United States | `us_ein` | United States EIN | - """ - - discount: Optional[Discount] = None - - discounts: List[Discount] - - due_date: datetime - """When the invoice payment is due.""" - - eligible_to_issue_at: Optional[datetime] = None - """ - If the invoice has a status of `draft`, this will be the time that the invoice - will be eligible to be issued, otherwise it will be `null`. If `auto-issue` is - true, the invoice will automatically begin issuing at this time. - """ - - hosted_invoice_url: Optional[str] = None - """A URL for the invoice portal.""" - - invoice_date: datetime - """The scheduled date of the invoice""" - - invoice_number: str - """Automatically generated invoice number to help track and reconcile invoices. - - Invoice numbers have a prefix such as `RFOBWG`. These can be sequential per - account or customer. - """ - - invoice_pdf: Optional[str] = None - """The link to download the PDF representation of the `Invoice`.""" - - issue_failed_at: Optional[datetime] = None - """ - If the invoice failed to issue, this will be the last time it failed to issue - (even if it is now in a different state.) - """ - - issued_at: Optional[datetime] = None - """ - If the invoice has been issued, this will be the time it transitioned to - `issued` (even if it is now in a different state.) - """ - - line_items: List[LineItem] - """The breakdown of prices in this invoice.""" - - maximum: Optional[Maximum] = None - - maximum_amount: Optional[str] = None - - memo: Optional[str] = None - """ - Free-form text which is available on the invoice PDF and the Orb invoice portal. - """ - - 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[Minimum] = None - - minimum_amount: Optional[str] = None - - paid_at: Optional[datetime] = None - """ - If the invoice has a status of `paid`, this gives a timestamp when the invoice - was paid. - """ - - payment_failed_at: Optional[datetime] = None - """ - If payment was attempted on this invoice but failed, this will be the time of - the most recent attempt. - """ - - payment_started_at: Optional[datetime] = None - """ - If payment was attempted on this invoice, this will be the start time of the - most recent attempt. This field is especially useful for delayed-notification - payment mechanisms (like bank transfers), where payment can take 3 days or more. - """ - - scheduled_issue_at: Optional[datetime] = None - """ - If the invoice is in draft, this timestamp will reflect when the invoice is - scheduled to be issued. - """ - - shipping_address: Optional[ShippingAddress] = None - - status: Literal["issued", "paid", "synced", "void", "draft"] - - subscription: Optional[Subscription] = None - - subtotal: str - """The total before any discounts and minimums are applied.""" - - sync_failed_at: Optional[datetime] = None - """ - If the invoice failed to sync, this will be the last time an external invoicing - provider sync was attempted. This field will always be `null` for invoices using - Orb Invoicing. - """ - - total: str - """The total after any minimums and discounts have been applied.""" - - voided_at: Optional[datetime] = None - """ - If the invoice has a status of `void`, this gives a timestamp when the invoice - was voided. - """ - - will_auto_issue: bool - """ - This is true if the invoice will be automatically issued in the future, and - false otherwise. - """ diff --git a/src/orb/types/invoice_create_params.py b/src/orb/types/invoice_create_params.py index aa4b32a2..e8515a25 100644 --- a/src/orb/types/invoice_create_params.py +++ b/src/orb/types/invoice_create_params.py @@ -7,8 +7,10 @@ from typing_extensions import Literal, Required, Annotated, TypedDict from .._utils import PropertyInfo +from .shared_params.discount import Discount +from .shared_params.unit_config import UnitConfig -__all__ = ["InvoiceCreateParams", "LineItem", "LineItemUnitConfig"] +__all__ = ["InvoiceCreateParams", "LineItem"] class InvoiceCreateParams(TypedDict, total=False): @@ -19,20 +21,19 @@ class InvoiceCreateParams(TypedDict, total=False): """ invoice_date: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """Optional invoice date to set. + """An ISO 8601 date or timestamp, interpreted in the customer's timezone. - Must be in the past, if not set, `invoice_date` is set to the current time in - the customer's timezone. + Must be in the past. If a date is set without a time, `invoice_date` is set to + midnight on the chosen date in the customer's timezone. """ line_items: Required[Iterable[LineItem]] - net_terms: Required[int] + auto_collection: Optional[bool] """ - 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 - 30 days to pay the invoice. + Determines whether this invoice will automatically attempt to charge a saved + payment method, if any. If not specified, the invoice inherits the customer's + auto_collection setting. """ customer_id: Optional[str] @@ -41,6 +42,15 @@ class InvoiceCreateParams(TypedDict, total=False): One of `customer_id` and `external_customer_id` are required. """ + discount: Optional[Discount] + """An optional discount to attach to the invoice.""" + + due_date: Annotated[Union[Union[str, date], Union[str, datetime], None], PropertyInfo(format="iso8601")] + """An optional custom due date for the invoice. + + If not set, the due date will be calculated based on the `net_terms` value. + """ + external_customer_id: Optional[str] """The `external_customer_id` of the `Customer` to create this invoice for. @@ -48,7 +58,10 @@ class InvoiceCreateParams(TypedDict, total=False): """ memo: Optional[str] - """An optional memo to attach to the invoice.""" + """An optional memo to attach to the invoice. + + If no memo is provided, we will attach the default memo + """ metadata: Optional[Dict[str, Optional[str]]] """User-specified key/value pairs for the resource. @@ -57,19 +70,24 @@ class InvoiceCreateParams(TypedDict, total=False): metadata mapping can be cleared by setting `metadata` to `null`. """ + net_terms: Optional[int] + """The net terms determines the due date of the invoice. + + Due date is calculated based on the invoice or issuance date, depending on the + account's configured due date calculation method. A value of '0' here represents + that the invoice is due on issue, whereas a value of '30' represents that the + customer has 30 days to pay the invoice. Do not set this field if you want to + set a custom due date. + """ + will_auto_issue: bool - """When true, this invoice will automatically be issued upon creation. + """When true, this invoice will be submitted for issuance upon creation. When false, the resulting invoice will require manual review to issue. Defaulted to false. """ -class LineItemUnitConfig(TypedDict, total=False): - unit_amount: Required[str] - """Rate per unit of usage""" - - class LineItem(TypedDict, total=False): end_date: Required[Annotated[Union[str, date], PropertyInfo(format="iso8601")]] """A date string to specify the line item's end date in the customer's timezone.""" @@ -87,4 +105,5 @@ class LineItem(TypedDict, total=False): start_date: Required[Annotated[Union[str, date], PropertyInfo(format="iso8601")]] """A date string to specify the line item's start date in the customer's timezone.""" - unit_config: Required[LineItemUnitConfig] + unit_config: Required[UnitConfig] + """Configuration for unit pricing""" 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 bcbd3eb2..c3d10a77 100644 --- a/src/orb/types/invoice_fetch_upcoming_response.py +++ b/src/orb/types/invoice_fetch_upcoming_response.py @@ -2,39 +2,42 @@ 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 .shared import Discount +from .._utils import PropertyInfo from .._models import BaseModel +from .shared.price import Price +from .shared.address import Address +from .shared.maximum import Maximum +from .shared.minimum import Minimum +from .shared.tax_amount import TaxAmount +from .shared.invoice_tiny import InvoiceTiny +from .shared.customer_tax_id import CustomerTaxID +from .shared.credit_note_tiny import CreditNoteTiny +from .shared.customer_minified import CustomerMinified +from .shared.tier_sub_line_item import TierSubLineItem +from .shared.other_sub_line_item import OtherSubLineItem +from .shared.matrix_sub_line_item import MatrixSubLineItem +from .shared.subscription_minified import SubscriptionMinified +from .shared.invoice_level_discount import InvoiceLevelDiscount +from .shared.monetary_maximum_adjustment import MonetaryMaximumAdjustment +from .shared.monetary_minimum_adjustment import MonetaryMinimumAdjustment +from .shared.monetary_usage_discount_adjustment import MonetaryUsageDiscountAdjustment +from .shared.monetary_amount_discount_adjustment import MonetaryAmountDiscountAdjustment +from .shared.monetary_percentage_discount_adjustment import MonetaryPercentageDiscountAdjustment __all__ = [ "InvoiceFetchUpcomingResponse", "AutoCollection", - "BillingAddress", "CreditNote", - "Customer", "CustomerBalanceTransaction", - "CustomerBalanceTransactionCreditNote", - "CustomerBalanceTransactionInvoice", - "CustomerTaxID", "LineItem", - "LineItemMaximum", - "LineItemMinimum", + "LineItemAdjustment", + "LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustment", + "LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentFilter", + "LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentTier", "LineItemSubLineItem", - "LineItemSubLineItemMatrixSubLineItem", - "LineItemSubLineItemMatrixSubLineItemGrouping", - "LineItemSubLineItemMatrixSubLineItemMatrixConfig", - "LineItemSubLineItemTierSubLineItem", - "LineItemSubLineItemTierSubLineItemGrouping", - "LineItemSubLineItemTierSubLineItemTierConfig", - "LineItemSubLineItemOtherSubLineItem", - "LineItemSubLineItemOtherSubLineItemGrouping", - "LineItemTaxAmount", - "Maximum", - "Minimum", - "ShippingAddress", - "Subscription", + "PaymentAttempt", ] @@ -49,6 +52,9 @@ class AutoCollection(BaseModel): is not enabled for this invoice, this field will be `null`. """ + num_attempts: Optional[int] = None + """Number of auto-collection payment attempts.""" + previously_attempted_at: Optional[datetime] = None """ If Orb has ever attempted payment auto-collection for this invoice, this field @@ -60,20 +66,6 @@ class AutoCollection(BaseModel): """ -class BillingAddress(BaseModel): - city: Optional[str] = None - - country: Optional[str] = None - - line1: Optional[str] = None - - line2: Optional[str] = None - - postal_code: Optional[str] = None - - state: Optional[str] = None - - class CreditNote(BaseModel): id: str @@ -95,22 +87,6 @@ class CreditNote(BaseModel): """ -class Customer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class CustomerBalanceTransactionCreditNote(BaseModel): - id: str - """The id of the Credit note""" - - -class CustomerBalanceTransactionInvoice(BaseModel): - id: str - """The Invoice id""" - - class CustomerBalanceTransaction(BaseModel): id: str """A unique id for this transaction.""" @@ -124,6 +100,8 @@ class CustomerBalanceTransaction(BaseModel): "credit_note_applied", "credit_note_voided", "overpayment_refund", + "external_payment", + "small_invoice_carryover", ] amount: str @@ -132,7 +110,7 @@ class CustomerBalanceTransaction(BaseModel): created_at: datetime """The creation time of this transaction.""" - credit_note: Optional[CustomerBalanceTransactionCreditNote] = None + credit_note: Optional[CreditNoteTiny] = None description: Optional[str] = None """An optional description provided for manual customer balance adjustments.""" @@ -143,7 +121,7 @@ class CustomerBalanceTransaction(BaseModel): customer's currency. """ - invoice: Optional[CustomerBalanceTransactionInvoice] = None + invoice: Optional[InvoiceTiny] = None starting_balance: str """ @@ -154,256 +132,128 @@ class CustomerBalanceTransaction(BaseModel): type: Literal["increment", "decrement"] -class CustomerTaxID(BaseModel): - country: Literal[ - "AD", - "AE", - "AT", - "AU", - "BE", - "BG", - "BR", - "CA", - "CH", - "CL", - "CY", - "CZ", - "DE", - "DK", - "EE", - "EG", - "ES", - "EU", - "FI", - "FR", - "GB", - "GE", - "GR", - "HK", - "HR", - "HU", - "ID", - "IE", - "IL", - "IN", - "IS", - "IT", - "JP", - "KE", - "KR", - "LI", - "LT", - "LU", - "LV", - "MT", - "MX", - "MY", - "NL", - "NO", - "NZ", - "PH", - "PL", - "PT", - "RO", - "RU", - "SA", - "SE", - "SG", - "SI", - "SK", - "TH", - "TR", - "TW", - "UA", - "US", - "ZA", - ] +class LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" - type: Literal[ - "ad_nrt", - "ae_trn", - "eu_vat", - "au_abn", - "au_arn", - "bg_uic", - "br_cnpj", - "br_cpf", - "ca_bn", - "ca_gst_hst", - "ca_pst_bc", - "ca_pst_mb", - "ca_pst_sk", - "ca_qst", - "ch_vat", - "cl_tin", - "eg_tin", - "es_cif", - "eu_oss_vat", - "gb_vat", - "ge_vat", - "hk_br", - "hu_tin", - "id_npwp", - "il_vat", - "in_gst", - "is_vat", - "jp_cn", - "jp_rn", - "jp_trn", - "ke_pin", - "kr_brn", - "li_uid", - "mx_rfc", - "my_frp", - "my_itn", - "my_sst", - "no_vat", - "nz_gst", - "ph_tin", - "ru_inn", - "ru_kpp", - "sa_vat", - "sg_gst", - "sg_uen", - "si_tin", - "th_vat", - "tr_tin", - "tw_vat", - "ua_vat", - "us_ein", - "za_vat", - ] + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" - value: str + values: List[str] + """The IDs or values that match this filter.""" -class LineItemMaximum(BaseModel): - applies_to_price_ids: List[str] - """List of price_ids that this maximum amount applies to. +class LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentTier(BaseModel): + """One band of a tiered percentage discount. - For plan/plan phase maximums, this can be a subset of prices. + Bounds are denominated in the discount's currency. + `lower_bound` is the exclusive start of the band and `upper_bound` is the inclusive end; + `upper_bound` is null only for the open-ended final tier. """ - maximum_amount: str - """Maximum amount applied""" + lower_bound: float + """Exclusive lower bound of cumulative spend for this tier.""" - -class LineItemMinimum(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. + percentage: float + """ + The percentage (between 0 and 1) discounted from spend that falls within this + tier. """ - minimum_amount: str - """Minimum amount applied""" - - -class LineItemSubLineItemMatrixSubLineItemGrouping(BaseModel): - key: str - - value: Optional[str] = None - """No value indicates the default group""" - - -class LineItemSubLineItemMatrixSubLineItemMatrixConfig(BaseModel): - dimension_values: List[Optional[str]] - """The ordered dimension values for this line item.""" - - -class LineItemSubLineItemMatrixSubLineItem(BaseModel): - amount: str - """The total amount for this sub line item.""" - - grouping: Optional[LineItemSubLineItemMatrixSubLineItemGrouping] = None - - matrix_config: LineItemSubLineItemMatrixSubLineItemMatrixConfig - - name: str - - quantity: float - - type: Literal["matrix"] - - -class LineItemSubLineItemTierSubLineItemGrouping(BaseModel): - key: str - - value: Optional[str] = None - """No value indicates the default group""" - - -class LineItemSubLineItemTierSubLineItemTierConfig(BaseModel): - first_unit: float + upper_bound: Optional[float] = None + """ + Inclusive upper bound of cumulative spend for this tier; null for the final + open-ended tier. + """ - last_unit: Optional[float] = None - unit_amount: str +class LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustment(BaseModel): + id: str + adjustment_type: Literal["tiered_percentage_discount"] -class LineItemSubLineItemTierSubLineItem(BaseModel): amount: str - """The total amount for this sub line item.""" - - grouping: Optional[LineItemSubLineItemTierSubLineItemGrouping] = None - - name: str - - quantity: float + """The value applied by an adjustment.""" - tier_config: LineItemSubLineItemTierSubLineItemTierConfig - - type: Literal["tier"] - - -class LineItemSubLineItemOtherSubLineItemGrouping(BaseModel): - key: str - - value: Optional[str] = None - """No value indicates the default group""" + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + filters: List[LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentFilter] + """The filters that determine which prices to apply this adjustment to.""" -class LineItemSubLineItemOtherSubLineItem(BaseModel): - amount: str - """The total amount for this sub line item.""" + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, false for adjustments that + apply to only one price. + """ - grouping: Optional[LineItemSubLineItemOtherSubLineItemGrouping] = None + reason: Optional[str] = None + """The reason for the adjustment.""" - name: str + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. - quantity: float + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ - type: Literal["'null'"] + tiers: List[LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentTier] + """ + The ordered, contiguous bands of cumulative eligible spend, each discounted at + its own percentage (progressive fill-a-tier), applied to the prices this + adjustment covers in a given billing period. + """ -LineItemSubLineItem = Union[ - LineItemSubLineItemMatrixSubLineItem, LineItemSubLineItemTierSubLineItem, LineItemSubLineItemOtherSubLineItem +LineItemAdjustment: TypeAlias = Annotated[ + Union[ + MonetaryUsageDiscountAdjustment, + MonetaryAmountDiscountAdjustment, + MonetaryPercentageDiscountAdjustment, + LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustment, + MonetaryMinimumAdjustment, + MonetaryMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), ] - -class LineItemTaxAmount(BaseModel): - amount: str - """The amount of additional tax incurred by this tax rate.""" - - tax_rate_description: str - """The human-readable description of the applied tax rate.""" - - tax_rate_percentage: Optional[str] = None - """The tax rate percentage, out of 100.""" +LineItemSubLineItem: TypeAlias = Annotated[ + Union[MatrixSubLineItem, TierSubLineItem, OtherSubLineItem], PropertyInfo(discriminator="type") +] class LineItem(BaseModel): id: str """A unique ID for this line item.""" + adjusted_subtotal: str + """ + The line amount after any adjustments and before overage conversion, credits and + partial invoicing. + """ + + adjustments: List[LineItemAdjustment] + """ + All adjustments applied to the line item in the order they were applied based on + invoice calculations (ie. usage discounts -> amount discounts -> percentage + discounts -> minimums -> maximums). + """ + amount: str - """The final amount after any discounts or minimums.""" + """ + The final amount for a line item after all adjustments and pre paid credits have + been applied. + """ - discount: Optional[Discount] = None + credits_applied: str + """The number of prepaid credits applied.""" end_date: datetime """The end date of the range of time applied for this line item's price.""" + filter: Optional[str] = None + """An additional filter that was used to calculate the usage for this line item.""" + grouping: Optional[str] = None """ [DEPRECATED] For configured prices that are split by a grouping key, this will @@ -411,18 +261,13 @@ class LineItem(BaseModel): values for this particular grouping. """ - maximum: Optional[LineItemMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[LineItemMinimum] = None - - minimum_amount: Optional[str] = None - name: str """The name of the price associated with this line item.""" - price: Optional[Price] = None + partially_invoiced_amount: str + """Any amount applied from a partial invoice""" + + 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 @@ -432,232 +277,12 @@ class LineItem(BaseModel): 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 - ... - } - ``` + For more on the types of prices, see + [the core concepts documentation](/core-concepts#plan-and-price) """ quantity: float + """Either the fixed fee quantity or the usage during the service period.""" start_date: datetime """The start date of the range of time applied for this line item's price.""" @@ -669,53 +294,44 @@ class LineItem(BaseModel): """ subtotal: str - """The line amount before any line item-specific discounts or minimums.""" + """The line amount before any adjustments.""" - tax_amounts: List[LineItemTaxAmount] + tax_amounts: List[TaxAmount] """An array of tax rates and their incurred tax amounts. Empty if no tax integration is configured. """ - -class Maximum(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. + usage_customer_ids: Optional[List[str]] = None """ - - maximum_amount: str - """Maximum amount applied""" - - -class Minimum(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. + A list of customer ids that were used to calculate the usage for this line item. """ - minimum_amount: str - """Minimum amount applied""" +class PaymentAttempt(BaseModel): + id: str + """The ID of the payment attempt.""" -class ShippingAddress(BaseModel): - city: Optional[str] = None + amount: str + """The amount of the payment attempt.""" - country: Optional[str] = None + created_at: datetime + """The time at which the payment attempt was created.""" - line1: Optional[str] = None + payment_provider: Optional[Literal["stripe", "adyen"]] = None + """The payment provider that attempted to collect the payment.""" - line2: Optional[str] = None + payment_provider_id: Optional[str] = None + """The ID of the payment attempt in the payment provider.""" - postal_code: Optional[str] = None + receipt_pdf: Optional[str] = None + """URL to the downloadable PDF version of the receipt. - state: Optional[str] = None + This field will be `null` for payment attempts that did not succeed. + """ - -class Subscription(BaseModel): - id: str + succeeded: bool + """Whether the payment attempt succeeded.""" class InvoiceFetchUpcomingResponse(BaseModel): @@ -729,7 +345,7 @@ class InvoiceFetchUpcomingResponse(BaseModel): auto_collection: AutoCollection - billing_address: Optional[BillingAddress] = None + billing_address: Optional[Address] = None created_at: datetime """The creation time of the resource in Orb.""" @@ -740,7 +356,7 @@ class InvoiceFetchUpcomingResponse(BaseModel): currency: str """An ISO 4217 currency string or `credits`""" - customer: Customer + customer: CustomerMinified customer_balance_transactions: List[CustomerBalanceTransaction] @@ -751,94 +367,167 @@ class InvoiceFetchUpcomingResponse(BaseModel): ### Supported Tax ID Countries and Types - | Country | Type | Description | - | -------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | - | Andorra | `ad_nrt` | Andorran NRT number | - | Australia | `au_abn` | Australian Business Number (AU ABN) | - | Australia | `au_arn` | Australian Taxation Office Reference Number | - | Austria | `eu_vat` | European VAT number | - | Belgium | `eu_vat` | European VAT number | - | Brazil | `br_cnpj` | Brazilian CNPJ number | - | Brazil | `br_cpf` | Brazilian CPF number | - | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | - | Bulgaria | `eu_vat` | European VAT number | - | Canada | `ca_bn` | Canadian BN | - | Canada | `ca_gst_hst` | Canadian GST/HST number | - | Canada | `ca_pst_bc` | Canadian PST number (British Columbia) | - | Canada | `ca_pst_mb` | Canadian PST number (Manitoba) | - | Canada | `ca_pst_sk` | Canadian PST number (Saskatchewan) | - | Canada | `ca_qst` | Canadian QST number (Québec) | - | Chile | `cl_tin` | Chilean TIN | - | Croatia | `eu_vat` | European VAT number | - | Cyprus | `eu_vat` | European VAT number | - | Czech Republic | `eu_vat` | European VAT number | - | Denmark | `eu_vat` | European VAT number | - | Egypt | `eg_tin` | Egyptian Tax Identification Number | - | Estonia | `eu_vat` | European VAT number | - | EU | `eu_oss_vat` | European One Stop Shop VAT number for non-Union scheme | - | Finland | `eu_vat` | European VAT number | - | France | `eu_vat` | European VAT number | - | Georgia | `ge_vat` | Georgian VAT | - | Germany | `eu_vat` | European VAT number | - | Greece | `eu_vat` | European VAT number | - | Hong Kong | `hk_br` | Hong Kong BR number | - | Hungary | `eu_vat` | European VAT number | - | Hungary | `hu_tin` | Hungary tax number (adószám) | - | Iceland | `is_vat` | Icelandic VAT | - | India | `in_gst` | Indian GST number | - | Indonesia | `id_npwp` | Indonesian NPWP number | - | Ireland | `eu_vat` | European VAT number | - | Israel | `il_vat` | Israel VAT | - | Italy | `eu_vat` | European VAT number | - | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | - | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | - | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | - | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | - | Latvia | `eu_vat` | European VAT number | - | Liechtenstein | `li_uid` | Liechtensteinian UID number | - | Lithuania | `eu_vat` | European VAT number | - | Luxembourg | `eu_vat` | European VAT number | - | Malaysia | `my_frp` | Malaysian FRP number | - | Malaysia | `my_itn` | Malaysian ITN | - | Malaysia | `my_sst` | Malaysian SST number | - | Malta | `eu_vat ` | European VAT number | - | Mexico | `mx_rfc` | Mexican RFC number | - | Netherlands | `eu_vat` | European VAT number | - | New Zealand | `nz_gst` | New Zealand GST number | - | Norway | `no_vat` | Norwegian VAT number | - | Philippines | `ph_tin ` | Philippines Tax Identification Number | - | Poland | `eu_vat` | European VAT number | - | Portugal | `eu_vat` | European VAT number | - | Romania | `eu_vat` | European VAT number | - | Russia | `ru_inn` | Russian INN | - | Russia | `ru_kpp` | Russian KPP | - | Saudi Arabia | `sg_gst` | Singaporean GST | - | Singapore | `sg_uen` | Singaporean UEN | - | Slovakia | `eu_vat` | European VAT number | - | Slovenia | `eu_vat` | European VAT number | - | Slovenia | `si_tin` | Slovenia tax number (davčna številka) | - | South Africa | `za_vat` | South African VAT number | - | South Korea | `kr_brn` | Korean BRN | - | Spain | `es_cif` | Spanish NIF number (previously Spanish CIF number) | - | Spain | `eu_vat` | European VAT number | - | Sweden | `eu_vat` | European VAT number | - | Switzerland | `ch_vat` | Switzerland VAT number | - | Taiwan | `tw_vat` | Taiwanese VAT | - | Thailand | `th_vat` | Thai VAT | - | Turkey | `tr_tin` | Turkish Tax Identification Number | - | Ukraine | `ua_vat` | Ukrainian VAT | - | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | - | United Kingdom | `eu_vat` | Northern Ireland VAT number | - | United Kingdom | `gb_vat` | United Kingdom VAT number | - | United States | `us_ein` | United States EIN | - """ - - discount: Optional[Discount] = None - - discounts: List[Discount] - - due_date: datetime - """When the invoice payment is due.""" + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | + """ + + discount: object + """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[InvoiceLevelDiscount] + + due_date: Optional[datetime] = None + """When the invoice payment is due. + + The due date is null if the invoice is not yet finalized. + """ eligible_to_issue_at: Optional[datetime] = None """ @@ -848,7 +537,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 60 days after the link is generated, or 30 days after the + invoice's due date — whichever is later. + """ invoice_number: str """Automatically generated invoice number to help track and reconcile invoices. @@ -860,6 +553,8 @@ class InvoiceFetchUpcomingResponse(BaseModel): invoice_pdf: Optional[str] = None """The link to download the PDF representation of the `Invoice`.""" + invoice_source: Literal["subscription", "partial", "one_off"] + issue_failed_at: Optional[datetime] = None """ If the invoice failed to issue, this will be the last time it failed to issue @@ -902,6 +597,9 @@ class InvoiceFetchUpcomingResponse(BaseModel): was paid. """ + payment_attempts: List[PaymentAttempt] + """A list of payment attempts associated with the invoice""" + payment_failed_at: Optional[datetime] = None """ If payment was attempted on this invoice but failed, this will be the time of @@ -921,11 +619,11 @@ class InvoiceFetchUpcomingResponse(BaseModel): scheduled to be issued. """ - shipping_address: Optional[ShippingAddress] = None + shipping_address: Optional[Address] = None status: Literal["issued", "paid", "synced", "void", "draft"] - subscription: Optional[Subscription] = None + subscription: Optional[SubscriptionMinified] = None subtotal: str """The total before any discounts and minimums are applied.""" diff --git a/src/orb/types/invoice_issue_params.py b/src/orb/types/invoice_issue_params.py new file mode 100644 index 00000000..e45510ef --- /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 that have 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/invoice_issue_summary_params.py b/src/orb/types/invoice_issue_summary_params.py new file mode 100644 index 00000000..2ef8061e --- /dev/null +++ b/src/orb/types/invoice_issue_summary_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__ = ["InvoiceIssueSummaryParams"] + + +class InvoiceIssueSummaryParams(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 that have 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/invoice_issue_summary_response.py b/src/orb/types/invoice_issue_summary_response.py new file mode 100644 index 00000000..1af9b415 --- /dev/null +++ b/src/orb/types/invoice_issue_summary_response.py @@ -0,0 +1,437 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel +from .shared.address import Address +from .shared.invoice_tiny import InvoiceTiny +from .shared.customer_tax_id import CustomerTaxID +from .shared.credit_note_tiny import CreditNoteTiny +from .shared.customer_minified import CustomerMinified +from .shared.subscription_minified import SubscriptionMinified + +__all__ = [ + "InvoiceIssueSummaryResponse", + "AutoCollection", + "CreditNote", + "CustomerBalanceTransaction", + "PaymentAttempt", +] + + +class AutoCollection(BaseModel): + enabled: Optional[bool] = None + """True only if auto-collection is enabled for this invoice.""" + + next_attempt_at: Optional[datetime] = None + """ + If the invoice is scheduled for auto-collection, this field will reflect when + the next attempt will occur. If dunning has been exhausted, or auto-collection + is not enabled for this invoice, this field will be `null`. + """ + + num_attempts: Optional[int] = None + """Number of auto-collection payment attempts.""" + + previously_attempted_at: Optional[datetime] = None + """ + If Orb has ever attempted payment auto-collection for this invoice, this field + will reflect when that attempt occurred. In conjunction with `next_attempt_at`, + this can be used to tell whether the invoice is currently in dunning (that is, + `previously_attempted_at` is non-null, and `next_attempt_time` is non-null), or + if dunning has been exhausted (`previously_attempted_at` is non-null, but + `next_attempt_time` is null). + """ + + +class CreditNote(BaseModel): + id: str + + credit_note_number: str + + memo: Optional[str] = None + """An optional memo supplied on the credit note.""" + + reason: str + + total: str + + type: str + + voided_at: Optional[datetime] = None + """ + If the credit note has a status of `void`, this gives a timestamp when the + credit note was voided. + """ + + +class CustomerBalanceTransaction(BaseModel): + id: str + """A unique id for this transaction.""" + + action: Literal[ + "applied_to_invoice", + "manual_adjustment", + "prorated_refund", + "revert_prorated_refund", + "return_from_voiding", + "credit_note_applied", + "credit_note_voided", + "overpayment_refund", + "external_payment", + "small_invoice_carryover", + ] + + amount: str + """The value of the amount changed in the transaction.""" + + created_at: datetime + """The creation time of this transaction.""" + + credit_note: Optional[CreditNoteTiny] = None + + description: Optional[str] = None + """An optional description provided for manual customer balance adjustments.""" + + ending_balance: str + """ + The new value of the customer's balance prior to the transaction, in the + customer's currency. + """ + + invoice: Optional[InvoiceTiny] = None + + starting_balance: str + """ + The original value of the customer's balance prior to the transaction, in the + customer's currency. + """ + + type: Literal["increment", "decrement"] + + +class PaymentAttempt(BaseModel): + id: str + """The ID of the payment attempt.""" + + amount: str + """The amount of the payment attempt.""" + + created_at: datetime + """The time at which the payment attempt was created.""" + + payment_provider: Optional[Literal["stripe", "adyen"]] = None + """The payment provider that attempted to collect the payment.""" + + payment_provider_id: Optional[str] = None + """The ID of the payment attempt in the payment provider.""" + + receipt_pdf: Optional[str] = None + """URL to the downloadable PDF version of the receipt. + + This field will be `null` for payment attempts that did not succeed. + """ + + succeeded: bool + """Whether the payment attempt succeeded.""" + + +class InvoiceIssueSummaryResponse(BaseModel): + """#InvoiceApiResourceWithoutLineItems""" + + id: str + + amount_due: str + """ + This is the final amount required to be charged to the customer and reflects the + application of the customer balance to the `total` of the invoice. + """ + + auto_collection: AutoCollection + + billing_address: Optional[Address] = None + + created_at: datetime + """The creation time of the resource in Orb.""" + + credit_notes: List[CreditNote] + """A list of credit notes associated with the invoice""" + + currency: str + """An ISO 4217 currency string or `credits`""" + + customer: CustomerMinified + + customer_balance_transactions: List[CustomerBalanceTransaction] + + customer_tax_id: Optional[CustomerTaxID] = None + """ + Tax IDs are commonly required to be displayed on customer invoices, which are + added to the headers of invoices. + + ### Supported Tax ID Countries and Types + + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | + """ + + due_date: Optional[datetime] = None + """When the invoice payment is due. + + The due date is null if the invoice is not yet finalized. + """ + + eligible_to_issue_at: Optional[datetime] = None + """ + If the invoice has a status of `draft`, this will be the time that the invoice + will be eligible to be issued, otherwise it will be `null`. If `auto-issue` is + true, the invoice will automatically begin issuing at this time. + """ + + hosted_invoice_url: Optional[str] = None + """A URL for the customer-facing invoice portal. + + This URL expires 60 days after the link is generated, or 30 days after the + invoice's due date — whichever is later. + """ + + invoice_date: datetime + """The scheduled date of the invoice""" + + invoice_number: str + """Automatically generated invoice number to help track and reconcile invoices. + + Invoice numbers have a prefix such as `RFOBWG`. These can be sequential per + account or customer. + """ + + invoice_pdf: Optional[str] = None + """The link to download the PDF representation of the `Invoice`.""" + + invoice_source: Literal["subscription", "partial", "one_off"] + + issue_failed_at: Optional[datetime] = None + """ + If the invoice failed to issue, this will be the last time it failed to issue + (even if it is now in a different state.) + """ + + issued_at: Optional[datetime] = None + """ + If the invoice has been issued, this will be the time it transitioned to + `issued` (even if it is now in a different state.) + """ + + memo: Optional[str] = None + """ + Free-form text which is available on the invoice PDF and the Orb invoice portal. + """ + + 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`. + """ + + paid_at: Optional[datetime] = None + """ + If the invoice has a status of `paid`, this gives a timestamp when the invoice + was paid. + """ + + payment_attempts: List[PaymentAttempt] + """A list of payment attempts associated with the invoice""" + + payment_failed_at: Optional[datetime] = None + """ + If payment was attempted on this invoice but failed, this will be the time of + the most recent attempt. + """ + + payment_started_at: Optional[datetime] = None + """ + If payment was attempted on this invoice, this will be the start time of the + most recent attempt. This field is especially useful for delayed-notification + payment mechanisms (like bank transfers), where payment can take 3 days or more. + """ + + scheduled_issue_at: Optional[datetime] = None + """ + If the invoice is in draft, this timestamp will reflect when the invoice is + scheduled to be issued. + """ + + shipping_address: Optional[Address] = None + + status: Literal["issued", "paid", "synced", "void", "draft"] + + subscription: Optional[SubscriptionMinified] = None + + sync_failed_at: Optional[datetime] = None + """ + If the invoice failed to sync, this will be the last time an external invoicing + provider sync was attempted. This field will always be `null` for invoices using + Orb Invoicing. + """ + + total: str + """The total after any minimums and discounts have been applied.""" + + voided_at: Optional[datetime] = None + """ + If the invoice has a status of `void`, this gives a timestamp when the invoice + was voided. + """ + + will_auto_issue: bool + """ + This is true if the invoice will be automatically issued in the future, and + false otherwise. + """ diff --git a/src/orb/types/invoice_line_item_create_params.py b/src/orb/types/invoice_line_item_create_params.py index 03016bfd..a633cc1e 100644 --- a/src/orb/types/invoice_line_item_create_params.py +++ b/src/orb/types/invoice_line_item_create_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union +from typing import Union, Optional from datetime import date from typing_extensions import Required, Annotated, TypedDict @@ -21,15 +21,26 @@ class InvoiceLineItemCreateParams(TypedDict, total=False): invoice_id: Required[str] """The id of the Invoice to add this line item.""" - name: Required[str] - """The item name associated with this line item. - - If an item with the same name exists in Orb, that item will be associated with - the line item. - """ - quantity: Required[float] """The number of units on the line item""" start_date: Required[Annotated[Union[str, date], PropertyInfo(format="iso8601")]] """A date string to specify the line item's start date in the customer's timezone.""" + + item_id: Optional[str] + """The id of the item to associate with this line item. + + If provided without `name`, the item's name will be used for the price/line + item. If provided with `name`, the item will be associated but `name` will be + used for the line item. At least one of `name` or `item_id` must be provided. + """ + + name: Optional[str] + """The name to use for the line item. + + If `item_id` is not provided, Orb will search for an item with this name. If + found, that item will be associated with the line item. If not found, a new item + will be created with this name. If `item_id` is provided, this name will be used + for the line item, but the item association will be based on `item_id`. At least + one of `name` or `item_id` must be provided. + """ diff --git a/src/orb/types/invoice_line_item_create_response.py b/src/orb/types/invoice_line_item_create_response.py index f62d6e21..f250c62d 100644 --- a/src/orb/types/invoice_line_item_create_response.py +++ b/src/orb/types/invoice_line_item_create_response.py @@ -2,154 +2,153 @@ from typing import List, Union, Optional from datetime import datetime -from typing_extensions import Literal +from typing_extensions import Literal, Annotated, TypeAlias -from .price import Price -from .shared import Discount +from .._utils import PropertyInfo from .._models import BaseModel +from .shared.price import Price +from .shared.tax_amount import TaxAmount +from .shared.tier_sub_line_item import TierSubLineItem +from .shared.other_sub_line_item import OtherSubLineItem +from .shared.matrix_sub_line_item import MatrixSubLineItem +from .shared.monetary_maximum_adjustment import MonetaryMaximumAdjustment +from .shared.monetary_minimum_adjustment import MonetaryMinimumAdjustment +from .shared.monetary_usage_discount_adjustment import MonetaryUsageDiscountAdjustment +from .shared.monetary_amount_discount_adjustment import MonetaryAmountDiscountAdjustment +from .shared.monetary_percentage_discount_adjustment import MonetaryPercentageDiscountAdjustment __all__ = [ "InvoiceLineItemCreateResponse", - "Maximum", - "Minimum", + "Adjustment", + "AdjustmentMonetaryTieredPercentageDiscountAdjustment", + "AdjustmentMonetaryTieredPercentageDiscountAdjustmentFilter", + "AdjustmentMonetaryTieredPercentageDiscountAdjustmentTier", "SubLineItem", - "SubLineItemMatrixSubLineItem", - "SubLineItemMatrixSubLineItemGrouping", - "SubLineItemMatrixSubLineItemMatrixConfig", - "SubLineItemTierSubLineItem", - "SubLineItemTierSubLineItemGrouping", - "SubLineItemTierSubLineItemTierConfig", - "SubLineItemOtherSubLineItem", - "SubLineItemOtherSubLineItemGrouping", - "TaxAmount", ] -class Maximum(BaseModel): - applies_to_price_ids: List[str] - """List of price_ids that this maximum amount applies to. +class AdjustmentMonetaryTieredPercentageDiscountAdjustmentFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" - For plan/plan phase maximums, this can be a subset of prices. - """ + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" - maximum_amount: str - """Maximum amount applied""" + values: List[str] + """The IDs or values that match this filter.""" -class Minimum(BaseModel): - applies_to_price_ids: List[str] - """List of price_ids that this minimum amount applies to. +class AdjustmentMonetaryTieredPercentageDiscountAdjustmentTier(BaseModel): + """One band of a tiered percentage discount. - For plan/plan phase minimums, this can be a subset of prices. + Bounds are denominated in the discount's currency. + `lower_bound` is the exclusive start of the band and `upper_bound` is the inclusive end; + `upper_bound` is null only for the open-ended final tier. """ - minimum_amount: str - """Minimum amount applied""" - - -class SubLineItemMatrixSubLineItemGrouping(BaseModel): - key: str - - value: Optional[str] = None - """No value indicates the default group""" - - -class SubLineItemMatrixSubLineItemMatrixConfig(BaseModel): - dimension_values: List[Optional[str]] - """The ordered dimension values for this line item.""" - - -class SubLineItemMatrixSubLineItem(BaseModel): - amount: str - """The total amount for this sub line item.""" - - grouping: Optional[SubLineItemMatrixSubLineItemGrouping] = None - - matrix_config: SubLineItemMatrixSubLineItemMatrixConfig - - name: str - - quantity: float - - type: Literal["matrix"] - - -class SubLineItemTierSubLineItemGrouping(BaseModel): - key: str - - value: Optional[str] = None - """No value indicates the default group""" - - -class SubLineItemTierSubLineItemTierConfig(BaseModel): - first_unit: float - - last_unit: Optional[float] = None - - unit_amount: str - - -class SubLineItemTierSubLineItem(BaseModel): - amount: str - """The total amount for this sub line item.""" - - grouping: Optional[SubLineItemTierSubLineItemGrouping] = None - - name: str - - quantity: float - - tier_config: SubLineItemTierSubLineItemTierConfig + lower_bound: float + """Exclusive lower bound of cumulative spend for this tier.""" - type: Literal["tier"] + percentage: float + """ + The percentage (between 0 and 1) discounted from spend that falls within this + tier. + """ + upper_bound: Optional[float] = None + """ + Inclusive upper bound of cumulative spend for this tier; null for the final + open-ended tier. + """ -class SubLineItemOtherSubLineItemGrouping(BaseModel): - key: str - value: Optional[str] = None - """No value indicates the default group""" +class AdjustmentMonetaryTieredPercentageDiscountAdjustment(BaseModel): + id: str + adjustment_type: Literal["tiered_percentage_discount"] -class SubLineItemOtherSubLineItem(BaseModel): amount: str - """The total amount for this sub line item.""" + """The value applied by an adjustment.""" - grouping: Optional[SubLineItemOtherSubLineItemGrouping] = None + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" - name: str + filters: List[AdjustmentMonetaryTieredPercentageDiscountAdjustmentFilter] + """The filters that determine which prices to apply this adjustment to.""" - quantity: float + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, false for adjustments that + apply to only one price. + """ - type: Literal["'null'"] + reason: Optional[str] = None + """The reason for the adjustment.""" + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. -SubLineItem = Union[SubLineItemMatrixSubLineItem, SubLineItemTierSubLineItem, SubLineItemOtherSubLineItem] + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ + tiers: List[AdjustmentMonetaryTieredPercentageDiscountAdjustmentTier] + """ + The ordered, contiguous bands of cumulative eligible spend, each discounted at + its own percentage (progressive fill-a-tier), applied to the prices this + adjustment covers in a given billing period. + """ -class TaxAmount(BaseModel): - amount: str - """The amount of additional tax incurred by this tax rate.""" - tax_rate_description: str - """The human-readable description of the applied tax rate.""" +Adjustment: TypeAlias = Annotated[ + Union[ + MonetaryUsageDiscountAdjustment, + MonetaryAmountDiscountAdjustment, + MonetaryPercentageDiscountAdjustment, + AdjustmentMonetaryTieredPercentageDiscountAdjustment, + MonetaryMinimumAdjustment, + MonetaryMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] - tax_rate_percentage: Optional[str] = None - """The tax rate percentage, out of 100.""" +SubLineItem: TypeAlias = Annotated[ + Union[MatrixSubLineItem, TierSubLineItem, OtherSubLineItem], PropertyInfo(discriminator="type") +] class InvoiceLineItemCreateResponse(BaseModel): id: str """A unique ID for this line item.""" + adjusted_subtotal: str + """ + The line amount after any adjustments and before overage conversion, credits and + partial invoicing. + """ + + adjustments: List[Adjustment] + """ + All adjustments applied to the line item in the order they were applied based on + invoice calculations (ie. usage discounts -> amount discounts -> percentage + discounts -> minimums -> maximums). + """ + amount: str - """The final amount after any discounts or minimums.""" + """ + The final amount for a line item after all adjustments and pre paid credits have + been applied. + """ - discount: Optional[Discount] = None + credits_applied: str + """The number of prepaid credits applied.""" end_date: datetime """The end date of the range of time applied for this line item's price.""" + filter: Optional[str] = None + """An additional filter that was used to calculate the usage for this line item.""" + grouping: Optional[str] = None """ [DEPRECATED] For configured prices that are split by a grouping key, this will @@ -157,18 +156,13 @@ class InvoiceLineItemCreateResponse(BaseModel): values for this particular grouping. """ - maximum: Optional[Maximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[Minimum] = None - - minimum_amount: Optional[str] = None - name: str """The name of the price associated with this line item.""" - price: Optional[Price] = None + partially_invoiced_amount: str + """Any amount applied from a partial invoice""" + + 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 @@ -178,232 +172,12 @@ class InvoiceLineItemCreateResponse(BaseModel): 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 - ... - } - ``` + For more on the types of prices, see + [the core concepts documentation](/core-concepts#plan-and-price) """ quantity: float + """Either the fixed fee quantity or the usage during the service period.""" start_date: datetime """The start date of the range of time applied for this line item's price.""" @@ -415,10 +189,15 @@ class InvoiceLineItemCreateResponse(BaseModel): """ subtotal: str - """The line amount before any line item-specific discounts or minimums.""" + """The line amount before any adjustments.""" tax_amounts: List[TaxAmount] """An array of tax rates and their incurred tax amounts. Empty if no tax integration is configured. """ + + usage_customer_ids: Optional[List[str]] = None + """ + A list of customer ids that were used to calculate the usage for this line item. + """ diff --git a/src/orb/types/invoice_list_params.py b/src/orb/types/invoice_list_params.py index 31bc4111..3bc832ee 100644 --- a/src/orb/types/invoice_list_params.py +++ b/src/orb/types/invoice_list_params.py @@ -32,6 +32,12 @@ class InvoiceListParams(TypedDict, total=False): due_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] due_date_window: Optional[str] + """Filters invoices by their due dates within a specific time range in the past. + + Specify the range as a number followed by 'd' (days) or 'm' (months). For + example, '7d' filters invoices due in the last 7 days, and '2m' filters those + due in the last 2 months. + """ due_date_gt: Annotated[Union[str, date, None], PropertyInfo(alias="due_date[gt]", format="iso8601")] diff --git a/src/orb/types/invoice_list_summary_params.py b/src/orb/types/invoice_list_summary_params.py new file mode 100644 index 00000000..41b86e65 --- /dev/null +++ b/src/orb/types/invoice_list_summary_params.py @@ -0,0 +1,63 @@ +# 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 date, datetime +from typing_extensions import Literal, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["InvoiceListSummaryParams"] + + +class InvoiceListSummaryParams(TypedDict, total=False): + amount: Optional[str] + + amount_gt: Annotated[Optional[str], PropertyInfo(alias="amount[gt]")] + + amount_lt: Annotated[Optional[str], PropertyInfo(alias="amount[lt]")] + + cursor: Optional[str] + """Cursor for pagination. + + This can be populated by the `next_cursor` value returned from the initial + request. + """ + + customer_id: Optional[str] + + date_type: Optional[Literal["due_date", "invoice_date"]] + + due_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + + due_date_window: Optional[str] + """Filters invoices by their due dates within a specific time range in the past. + + Specify the range as a number followed by 'd' (days) or 'm' (months). For + example, '7d' filters invoices due in the last 7 days, and '2m' filters those + due in the last 2 months. + """ + + due_date_gt: Annotated[Union[str, date, None], PropertyInfo(alias="due_date[gt]", format="iso8601")] + + due_date_lt: Annotated[Union[str, date, None], PropertyInfo(alias="due_date[lt]", format="iso8601")] + + external_customer_id: Optional[str] + + invoice_date_gt: Annotated[Union[str, datetime, None], PropertyInfo(alias="invoice_date[gt]", format="iso8601")] + + invoice_date_gte: Annotated[Union[str, datetime, None], PropertyInfo(alias="invoice_date[gte]", format="iso8601")] + + invoice_date_lt: Annotated[Union[str, datetime, None], PropertyInfo(alias="invoice_date[lt]", format="iso8601")] + + invoice_date_lte: Annotated[Union[str, datetime, None], PropertyInfo(alias="invoice_date[lte]", format="iso8601")] + + is_recurring: Optional[bool] + + limit: int + """The number of items to fetch. Defaults to 20.""" + + status: Optional[Literal["draft", "issued", "paid", "synced", "void"]] + + subscription_id: Optional[str] diff --git a/src/orb/types/invoice_list_summary_response.py b/src/orb/types/invoice_list_summary_response.py new file mode 100644 index 00000000..76abc946 --- /dev/null +++ b/src/orb/types/invoice_list_summary_response.py @@ -0,0 +1,431 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel +from .shared.address import Address +from .shared.invoice_tiny import InvoiceTiny +from .shared.customer_tax_id import CustomerTaxID +from .shared.credit_note_tiny import CreditNoteTiny +from .shared.customer_minified import CustomerMinified +from .shared.subscription_minified import SubscriptionMinified + +__all__ = ["InvoiceListSummaryResponse", "AutoCollection", "CreditNote", "CustomerBalanceTransaction", "PaymentAttempt"] + + +class AutoCollection(BaseModel): + enabled: Optional[bool] = None + """True only if auto-collection is enabled for this invoice.""" + + next_attempt_at: Optional[datetime] = None + """ + If the invoice is scheduled for auto-collection, this field will reflect when + the next attempt will occur. If dunning has been exhausted, or auto-collection + is not enabled for this invoice, this field will be `null`. + """ + + num_attempts: Optional[int] = None + """Number of auto-collection payment attempts.""" + + previously_attempted_at: Optional[datetime] = None + """ + If Orb has ever attempted payment auto-collection for this invoice, this field + will reflect when that attempt occurred. In conjunction with `next_attempt_at`, + this can be used to tell whether the invoice is currently in dunning (that is, + `previously_attempted_at` is non-null, and `next_attempt_time` is non-null), or + if dunning has been exhausted (`previously_attempted_at` is non-null, but + `next_attempt_time` is null). + """ + + +class CreditNote(BaseModel): + id: str + + credit_note_number: str + + memo: Optional[str] = None + """An optional memo supplied on the credit note.""" + + reason: str + + total: str + + type: str + + voided_at: Optional[datetime] = None + """ + If the credit note has a status of `void`, this gives a timestamp when the + credit note was voided. + """ + + +class CustomerBalanceTransaction(BaseModel): + id: str + """A unique id for this transaction.""" + + action: Literal[ + "applied_to_invoice", + "manual_adjustment", + "prorated_refund", + "revert_prorated_refund", + "return_from_voiding", + "credit_note_applied", + "credit_note_voided", + "overpayment_refund", + "external_payment", + "small_invoice_carryover", + ] + + amount: str + """The value of the amount changed in the transaction.""" + + created_at: datetime + """The creation time of this transaction.""" + + credit_note: Optional[CreditNoteTiny] = None + + description: Optional[str] = None + """An optional description provided for manual customer balance adjustments.""" + + ending_balance: str + """ + The new value of the customer's balance prior to the transaction, in the + customer's currency. + """ + + invoice: Optional[InvoiceTiny] = None + + starting_balance: str + """ + The original value of the customer's balance prior to the transaction, in the + customer's currency. + """ + + type: Literal["increment", "decrement"] + + +class PaymentAttempt(BaseModel): + id: str + """The ID of the payment attempt.""" + + amount: str + """The amount of the payment attempt.""" + + created_at: datetime + """The time at which the payment attempt was created.""" + + payment_provider: Optional[Literal["stripe", "adyen"]] = None + """The payment provider that attempted to collect the payment.""" + + payment_provider_id: Optional[str] = None + """The ID of the payment attempt in the payment provider.""" + + receipt_pdf: Optional[str] = None + """URL to the downloadable PDF version of the receipt. + + This field will be `null` for payment attempts that did not succeed. + """ + + succeeded: bool + """Whether the payment attempt succeeded.""" + + +class InvoiceListSummaryResponse(BaseModel): + """#InvoiceApiResourceWithoutLineItems""" + + id: str + + amount_due: str + """ + This is the final amount required to be charged to the customer and reflects the + application of the customer balance to the `total` of the invoice. + """ + + auto_collection: AutoCollection + + billing_address: Optional[Address] = None + + created_at: datetime + """The creation time of the resource in Orb.""" + + credit_notes: List[CreditNote] + """A list of credit notes associated with the invoice""" + + currency: str + """An ISO 4217 currency string or `credits`""" + + customer: CustomerMinified + + customer_balance_transactions: List[CustomerBalanceTransaction] + + customer_tax_id: Optional[CustomerTaxID] = None + """ + Tax IDs are commonly required to be displayed on customer invoices, which are + added to the headers of invoices. + + ### Supported Tax ID Countries and Types + + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | + """ + + due_date: Optional[datetime] = None + """When the invoice payment is due. + + The due date is null if the invoice is not yet finalized. + """ + + eligible_to_issue_at: Optional[datetime] = None + """ + If the invoice has a status of `draft`, this will be the time that the invoice + will be eligible to be issued, otherwise it will be `null`. If `auto-issue` is + true, the invoice will automatically begin issuing at this time. + """ + + hosted_invoice_url: Optional[str] = None + """A URL for the customer-facing invoice portal. + + This URL expires 60 days after the link is generated, or 30 days after the + invoice's due date — whichever is later. + """ + + invoice_date: datetime + """The scheduled date of the invoice""" + + invoice_number: str + """Automatically generated invoice number to help track and reconcile invoices. + + Invoice numbers have a prefix such as `RFOBWG`. These can be sequential per + account or customer. + """ + + invoice_pdf: Optional[str] = None + """The link to download the PDF representation of the `Invoice`.""" + + invoice_source: Literal["subscription", "partial", "one_off"] + + issue_failed_at: Optional[datetime] = None + """ + If the invoice failed to issue, this will be the last time it failed to issue + (even if it is now in a different state.) + """ + + issued_at: Optional[datetime] = None + """ + If the invoice has been issued, this will be the time it transitioned to + `issued` (even if it is now in a different state.) + """ + + memo: Optional[str] = None + """ + Free-form text which is available on the invoice PDF and the Orb invoice portal. + """ + + 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`. + """ + + paid_at: Optional[datetime] = None + """ + If the invoice has a status of `paid`, this gives a timestamp when the invoice + was paid. + """ + + payment_attempts: List[PaymentAttempt] + """A list of payment attempts associated with the invoice""" + + payment_failed_at: Optional[datetime] = None + """ + If payment was attempted on this invoice but failed, this will be the time of + the most recent attempt. + """ + + payment_started_at: Optional[datetime] = None + """ + If payment was attempted on this invoice, this will be the start time of the + most recent attempt. This field is especially useful for delayed-notification + payment mechanisms (like bank transfers), where payment can take 3 days or more. + """ + + scheduled_issue_at: Optional[datetime] = None + """ + If the invoice is in draft, this timestamp will reflect when the invoice is + scheduled to be issued. + """ + + shipping_address: Optional[Address] = None + + status: Literal["issued", "paid", "synced", "void", "draft"] + + subscription: Optional[SubscriptionMinified] = None + + sync_failed_at: Optional[datetime] = None + """ + If the invoice failed to sync, this will be the last time an external invoicing + provider sync was attempted. This field will always be `null` for invoices using + Orb Invoicing. + """ + + total: str + """The total after any minimums and discounts have been applied.""" + + voided_at: Optional[datetime] = None + """ + If the invoice has a status of `void`, this gives a timestamp when the invoice + was voided. + """ + + will_auto_issue: bool + """ + This is true if the invoice will be automatically issued in the future, and + false otherwise. + """ diff --git a/src/orb/types/invoice_pay_params.py b/src/orb/types/invoice_pay_params.py new file mode 100644 index 00000000..e7a883d8 --- /dev/null +++ b/src/orb/types/invoice_pay_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["InvoicePayParams"] + + +class InvoicePayParams(TypedDict, total=False): + shared_payment_token_id: Required[str] + """The ID of a shared payment token granted by an agent to use for this payment.""" diff --git a/src/orb/types/invoice_update_params.py b/src/orb/types/invoice_update_params.py new file mode 100644 index 00000000..30367bce --- /dev/null +++ b/src/orb/types/invoice_update_params.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from datetime import date, datetime +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["InvoiceUpdateParams"] + + +class InvoiceUpdateParams(TypedDict, total=False): + auto_collection: Optional[bool] + """ + Determines whether this invoice will automatically attempt to charge a saved + payment method, if any. Can only be modified on draft invoices. If not + specified, the invoice's existing setting is unchanged. + """ + + due_date: Annotated[Union[Union[str, date], Union[str, datetime], None], PropertyInfo(format="iso8601")] + """An optional custom due date for the invoice. + + If not set, the due date will be calculated based on the `net_terms` value. + """ + + invoice_date: Annotated[Union[Union[str, date], Union[str, datetime], None], PropertyInfo(format="iso8601")] + """The date of the invoice. Can only be modified for one-off draft invoices.""" + + 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`. + """ + + net_terms: Optional[int] + """The net terms determines the due date of the invoice. + + Due date is calculated based on the invoice or issuance date, depending on the + account's configured due date calculation method. A value of '0' here represents + that the invoice is due on issue, whereas a value of '30' represents that the + customer has 30 days to pay the invoice. Do not set this field if you want to + set a custom due date. + """ diff --git a/src/orb/types/item.py b/src/orb/types/item.py index ad22a1dd..6f4fcb32 100644 --- a/src/orb/types/item.py +++ b/src/orb/types/item.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import Dict, List, Optional from datetime import datetime from typing_extensions import Literal @@ -10,16 +10,48 @@ class ExternalConnection(BaseModel): - external_connection_name: Literal["stripe", "quickbooks", "bill.com", "netsuite", "taxjar", "avalara", "anrok"] + """ + Represents a connection between an Item and an external system for invoicing or tax calculation purposes. + """ + + external_connection_name: Literal[ + "stripe", "quickbooks", "bill.com", "netsuite", "taxjar", "avalara", "anrok", "numeral", "stripe_tax" + ] + """The name of the external system this item is connected to.""" external_entity_id: str + """The identifier of this item in the external system.""" class Item(BaseModel): + """The Item resource represents a sellable product or good. + + Items are associated with all line items, billable metrics, + and prices and are used for defining external sync behavior for invoices and tax calculation purposes. + """ + id: str + """The Orb-assigned unique identifier for the item.""" created_at: datetime + """The time at which the item was created.""" external_connections: List[ExternalConnection] + """ + A list of external connections for this item, used to sync with external + invoicing and tax systems. + """ + + 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`. + """ name: str + """The name of the item.""" + + archived_at: Optional[datetime] = None + """The time at which the item was archived. If null, the item is not archived.""" diff --git a/src/orb/types/item_create_params.py b/src/orb/types/item_create_params.py index 8b45e468..178b7e23 100644 --- a/src/orb/types/item_create_params.py +++ b/src/orb/types/item_create_params.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Dict, Optional from typing_extensions import Required, TypedDict __all__ = ["ItemCreateParams"] @@ -10,3 +11,10 @@ class ItemCreateParams(TypedDict, total=False): name: Required[str] """The name of the item.""" + + 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`. + """ diff --git a/src/orb/types/item_update_params.py b/src/orb/types/item_update_params.py new file mode 100644 index 00000000..939b406c --- /dev/null +++ b/src/orb/types/item_update_params.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ItemUpdateParams", "ExternalConnection"] + + +class ItemUpdateParams(TypedDict, total=False): + external_connections: Optional[Iterable[ExternalConnection]] + + 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`. + """ + + name: Optional[str] + + +class ExternalConnection(TypedDict, total=False): + """ + Represents a connection between an Item and an external system for invoicing or tax calculation purposes. + """ + + external_connection_name: Required[ + Literal["stripe", "quickbooks", "bill.com", "netsuite", "taxjar", "avalara", "anrok", "numeral", "stripe_tax"] + ] + """The name of the external system this item is connected to.""" + + external_entity_id: Required[str] + """The identifier of this item in the external system.""" diff --git a/src/orb/types/license_create_params.py b/src/orb/types/license_create_params.py new file mode 100644 index 00000000..9af3d84e --- /dev/null +++ b/src/orb/types/license_create_params.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import date +from typing_extensions import Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["LicenseCreateParams"] + + +class LicenseCreateParams(TypedDict, total=False): + external_license_id: Required[str] + """The external identifier for the license.""" + + license_type_id: Required[str] + + subscription_id: Required[str] + + end_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """The end date of the license. + + If not provided, the license will remain active until deactivated. + """ + + start_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """The start date of the license. + + If not provided, defaults to start of day today in the customer's timezone. + """ diff --git a/src/orb/types/license_create_response.py b/src/orb/types/license_create_response.py new file mode 100644 index 00000000..75190ad6 --- /dev/null +++ b/src/orb/types/license_create_response.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["LicenseCreateResponse"] + + +class LicenseCreateResponse(BaseModel): + id: str + + end_date: Optional[datetime] = None + + external_license_id: str + + license_type_id: str + + start_date: datetime + + status: Literal["active", "inactive"] + + subscription_id: str diff --git a/src/orb/types/license_deactivate_params.py b/src/orb/types/license_deactivate_params.py new file mode 100644 index 00000000..ef994d75 --- /dev/null +++ b/src/orb/types/license_deactivate_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import date +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["LicenseDeactivateParams"] + + +class LicenseDeactivateParams(TypedDict, total=False): + end_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """The date to deactivate the license. + + If not provided, defaults to end of day today in the customer's timezone. + """ diff --git a/src/orb/types/license_deactivate_response.py b/src/orb/types/license_deactivate_response.py new file mode 100644 index 00000000..ae3cd8b0 --- /dev/null +++ b/src/orb/types/license_deactivate_response.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["LicenseDeactivateResponse"] + + +class LicenseDeactivateResponse(BaseModel): + id: str + + end_date: Optional[datetime] = None + + external_license_id: str + + license_type_id: str + + start_date: datetime + + status: Literal["active", "inactive"] + + subscription_id: str diff --git a/src/orb/types/license_list_params.py b/src/orb/types/license_list_params.py new file mode 100644 index 00000000..9d012a1d --- /dev/null +++ b/src/orb/types/license_list_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["LicenseListParams"] + + +class LicenseListParams(TypedDict, total=False): + subscription_id: Required[str] + + cursor: Optional[str] + """Cursor for pagination. + + This can be populated by the `next_cursor` value returned from the initial + request. + """ + + external_license_id: Optional[str] + + license_type_id: Optional[str] + + limit: int + """The number of items to fetch. Defaults to 20.""" + + status: Optional[Literal["active", "inactive"]] diff --git a/src/orb/types/license_list_response.py b/src/orb/types/license_list_response.py new file mode 100644 index 00000000..974882ff --- /dev/null +++ b/src/orb/types/license_list_response.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["LicenseListResponse"] + + +class LicenseListResponse(BaseModel): + id: str + + end_date: Optional[datetime] = None + + external_license_id: str + + license_type_id: str + + start_date: datetime + + status: Literal["active", "inactive"] + + subscription_id: str diff --git a/src/orb/types/license_retrieve_by_external_id_params.py b/src/orb/types/license_retrieve_by_external_id_params.py new file mode 100644 index 00000000..5d88ba3d --- /dev/null +++ b/src/orb/types/license_retrieve_by_external_id_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["LicenseRetrieveByExternalIDParams"] + + +class LicenseRetrieveByExternalIDParams(TypedDict, total=False): + license_type_id: Required[str] + """The ID of the license type to fetch the license for.""" + + subscription_id: Required[str] + """The ID of the subscription to fetch the license for.""" diff --git a/src/orb/types/license_retrieve_by_external_id_response.py b/src/orb/types/license_retrieve_by_external_id_response.py new file mode 100644 index 00000000..0c766a3f --- /dev/null +++ b/src/orb/types/license_retrieve_by_external_id_response.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["LicenseRetrieveByExternalIDResponse"] + + +class LicenseRetrieveByExternalIDResponse(BaseModel): + id: str + + end_date: Optional[datetime] = None + + external_license_id: str + + license_type_id: str + + start_date: datetime + + status: Literal["active", "inactive"] + + subscription_id: str diff --git a/src/orb/types/license_retrieve_response.py b/src/orb/types/license_retrieve_response.py new file mode 100644 index 00000000..b62f1f29 --- /dev/null +++ b/src/orb/types/license_retrieve_response.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["LicenseRetrieveResponse"] + + +class LicenseRetrieveResponse(BaseModel): + id: str + + end_date: Optional[datetime] = None + + external_license_id: str + + license_type_id: str + + start_date: datetime + + status: Literal["active", "inactive"] + + subscription_id: str diff --git a/src/orb/types/license_type_create_params.py b/src/orb/types/license_type_create_params.py new file mode 100644 index 00000000..978187ab --- /dev/null +++ b/src/orb/types/license_type_create_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 Required, TypedDict + +__all__ = ["LicenseTypeCreateParams"] + + +class LicenseTypeCreateParams(TypedDict, total=False): + grouping_key: Required[str] + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: Required[str] + """The name of the license type.""" diff --git a/src/orb/types/license_type_create_response.py b/src/orb/types/license_type_create_response.py new file mode 100644 index 00000000..cd526aaf --- /dev/null +++ b/src/orb/types/license_type_create_response.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["LicenseTypeCreateResponse"] + + +class LicenseTypeCreateResponse(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" diff --git a/src/orb/types/license_type_list_params.py b/src/orb/types/license_type_list_params.py new file mode 100644 index 00000000..9f312406 --- /dev/null +++ b/src/orb/types/license_type_list_params.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +__all__ = ["LicenseTypeListParams"] + + +class LicenseTypeListParams(TypedDict, total=False): + 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.""" diff --git a/src/orb/types/license_type_list_response.py b/src/orb/types/license_type_list_response.py new file mode 100644 index 00000000..8e672e86 --- /dev/null +++ b/src/orb/types/license_type_list_response.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["LicenseTypeListResponse"] + + +class LicenseTypeListResponse(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" diff --git a/src/orb/types/license_type_retrieve_response.py b/src/orb/types/license_type_retrieve_response.py new file mode 100644 index 00000000..36b1cdac --- /dev/null +++ b/src/orb/types/license_type_retrieve_response.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["LicenseTypeRetrieveResponse"] + + +class LicenseTypeRetrieveResponse(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" diff --git a/src/orb/types/licenses/__init__.py b/src/orb/types/licenses/__init__.py new file mode 100644 index 00000000..d87379d6 --- /dev/null +++ b/src/orb/types/licenses/__init__.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .usage_get_usage_params import UsageGetUsageParams as UsageGetUsageParams +from .usage_get_usage_response import UsageGetUsageResponse as UsageGetUsageResponse +from .usage_get_all_usage_params import UsageGetAllUsageParams as UsageGetAllUsageParams +from .usage_get_all_usage_response import UsageGetAllUsageResponse as UsageGetAllUsageResponse +from .external_license_get_usage_params import ExternalLicenseGetUsageParams as ExternalLicenseGetUsageParams +from .external_license_get_usage_response import ExternalLicenseGetUsageResponse as ExternalLicenseGetUsageResponse diff --git a/src/orb/types/licenses/external_license_get_usage_params.py b/src/orb/types/licenses/external_license_get_usage_params.py new file mode 100644 index 00000000..5d714b10 --- /dev/null +++ b/src/orb/types/licenses/external_license_get_usage_params.py @@ -0,0 +1,43 @@ +# 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 date +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["ExternalLicenseGetUsageParams"] + + +class ExternalLicenseGetUsageParams(TypedDict, total=False): + license_type_id: Required[str] + """The license type ID to filter licenses by.""" + + subscription_id: Required[str] + """The subscription ID to get license usage for.""" + + cursor: Optional[str] + """Pagination cursor from a previous request.""" + + end_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """End date for the usage period (YYYY-MM-DD). + + Defaults to end of current billing period. + """ + + group_by: Optional[str] + """How to group the results. + + Valid values: 'license', 'day'. Can be combined (e.g., 'license,day'). + """ + + limit: int + """Maximum number of rows in the response data (default 20, max 100).""" + + start_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """Start date for the usage period (YYYY-MM-DD). + + Defaults to start of current billing period. + """ diff --git a/src/orb/types/licenses/external_license_get_usage_response.py b/src/orb/types/licenses/external_license_get_usage_response.py new file mode 100644 index 00000000..d7c0d600 --- /dev/null +++ b/src/orb/types/licenses/external_license_get_usage_response.py @@ -0,0 +1,66 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import date + +from ..._models import BaseModel +from ..shared.pagination_metadata import PaginationMetadata + +__all__ = ["ExternalLicenseGetUsageResponse", "Data"] + + +class Data(BaseModel): + """ + The LicenseUsage resource represents usage and remaining credits for a license over a date range. + + When grouped by 'day' only, license_id and external_license_id will be null as the data + is aggregated across all licenses. + """ + + allocated_credits: float + """The total credits allocated to this license for the period.""" + + consumed_credits: float + """The credits consumed by this license for the period.""" + + end_date: date + """The end date of the usage period.""" + + license_type_id: str + """The unique identifier for the license type.""" + + pricing_unit: str + """The pricing unit for the credits (e.g., 'credits').""" + + remaining_credits: float + """The remaining credits available for this license (allocated - consumed).""" + + start_date: date + """The start date of the usage period.""" + + subscription_id: str + """The unique identifier for the subscription.""" + + allocation_eligible_credits: Optional[float] = None + """ + Credits consumed while the license was active (eligible for individual + allocation deduction). + """ + + external_license_id: Optional[str] = None + """The external identifier for the license. Null when grouped by day only.""" + + license_id: Optional[str] = None + """The unique identifier for the license. Null when grouped by day only.""" + + shared_pool_credits: Optional[float] = None + """ + Credits consumed while the license was inactive (draws from shared pool, not + individual allocation). + """ + + +class ExternalLicenseGetUsageResponse(BaseModel): + data: List[Data] + + pagination_metadata: PaginationMetadata diff --git a/src/orb/types/licenses/usage_get_all_usage_params.py b/src/orb/types/licenses/usage_get_all_usage_params.py new file mode 100644 index 00000000..4fbdadab --- /dev/null +++ b/src/orb/types/licenses/usage_get_all_usage_params.py @@ -0,0 +1,43 @@ +# 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 date +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["UsageGetAllUsageParams"] + + +class UsageGetAllUsageParams(TypedDict, total=False): + license_type_id: Required[str] + """The license type ID to filter licenses by.""" + + subscription_id: Required[str] + """The subscription ID to get license usage for.""" + + cursor: Optional[str] + """Pagination cursor from a previous request.""" + + end_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """End date for the usage period (YYYY-MM-DD). + + Defaults to end of current billing period. + """ + + group_by: Optional[str] + """How to group the results. + + Valid values: 'license', 'day'. Can be combined (e.g., 'license,day'). + """ + + limit: int + """Maximum number of rows in the response data (default 20, max 100).""" + + start_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """Start date for the usage period (YYYY-MM-DD). + + Defaults to start of current billing period. + """ diff --git a/src/orb/types/licenses/usage_get_all_usage_response.py b/src/orb/types/licenses/usage_get_all_usage_response.py new file mode 100644 index 00000000..ed6e9adf --- /dev/null +++ b/src/orb/types/licenses/usage_get_all_usage_response.py @@ -0,0 +1,66 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import date + +from ..._models import BaseModel +from ..shared.pagination_metadata import PaginationMetadata + +__all__ = ["UsageGetAllUsageResponse", "Data"] + + +class Data(BaseModel): + """ + The LicenseUsage resource represents usage and remaining credits for a license over a date range. + + When grouped by 'day' only, license_id and external_license_id will be null as the data + is aggregated across all licenses. + """ + + allocated_credits: float + """The total credits allocated to this license for the period.""" + + consumed_credits: float + """The credits consumed by this license for the period.""" + + end_date: date + """The end date of the usage period.""" + + license_type_id: str + """The unique identifier for the license type.""" + + pricing_unit: str + """The pricing unit for the credits (e.g., 'credits').""" + + remaining_credits: float + """The remaining credits available for this license (allocated - consumed).""" + + start_date: date + """The start date of the usage period.""" + + subscription_id: str + """The unique identifier for the subscription.""" + + allocation_eligible_credits: Optional[float] = None + """ + Credits consumed while the license was active (eligible for individual + allocation deduction). + """ + + external_license_id: Optional[str] = None + """The external identifier for the license. Null when grouped by day only.""" + + license_id: Optional[str] = None + """The unique identifier for the license. Null when grouped by day only.""" + + shared_pool_credits: Optional[float] = None + """ + Credits consumed while the license was inactive (draws from shared pool, not + individual allocation). + """ + + +class UsageGetAllUsageResponse(BaseModel): + data: List[Data] + + pagination_metadata: PaginationMetadata diff --git a/src/orb/types/licenses/usage_get_usage_params.py b/src/orb/types/licenses/usage_get_usage_params.py new file mode 100644 index 00000000..7837e423 --- /dev/null +++ b/src/orb/types/licenses/usage_get_usage_params.py @@ -0,0 +1,37 @@ +# 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 date +from typing_extensions import Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["UsageGetUsageParams"] + + +class UsageGetUsageParams(TypedDict, total=False): + cursor: Optional[str] + """Pagination cursor from a previous request.""" + + end_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """End date for the usage period (YYYY-MM-DD). + + Defaults to end of current billing period. + """ + + group_by: Optional[str] + """How to group the results. + + Valid values: 'license', 'day'. Can be combined (e.g., 'license,day'). + """ + + limit: int + """Maximum number of rows in the response data (default 20, max 100).""" + + start_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """Start date for the usage period (YYYY-MM-DD). + + Defaults to start of current billing period. + """ diff --git a/src/orb/types/licenses/usage_get_usage_response.py b/src/orb/types/licenses/usage_get_usage_response.py new file mode 100644 index 00000000..5e69870c --- /dev/null +++ b/src/orb/types/licenses/usage_get_usage_response.py @@ -0,0 +1,66 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import date + +from ..._models import BaseModel +from ..shared.pagination_metadata import PaginationMetadata + +__all__ = ["UsageGetUsageResponse", "Data"] + + +class Data(BaseModel): + """ + The LicenseUsage resource represents usage and remaining credits for a license over a date range. + + When grouped by 'day' only, license_id and external_license_id will be null as the data + is aggregated across all licenses. + """ + + allocated_credits: float + """The total credits allocated to this license for the period.""" + + consumed_credits: float + """The credits consumed by this license for the period.""" + + end_date: date + """The end date of the usage period.""" + + license_type_id: str + """The unique identifier for the license type.""" + + pricing_unit: str + """The pricing unit for the credits (e.g., 'credits').""" + + remaining_credits: float + """The remaining credits available for this license (allocated - consumed).""" + + start_date: date + """The start date of the usage period.""" + + subscription_id: str + """The unique identifier for the subscription.""" + + allocation_eligible_credits: Optional[float] = None + """ + Credits consumed while the license was active (eligible for individual + allocation deduction). + """ + + external_license_id: Optional[str] = None + """The external identifier for the license. Null when grouped by day only.""" + + license_id: Optional[str] = None + """The unique identifier for the license. Null when grouped by day only.""" + + shared_pool_credits: Optional[float] = None + """ + Credits consumed while the license was inactive (draws from shared pool, not + individual allocation). + """ + + +class UsageGetUsageResponse(BaseModel): + data: List[Data] + + pagination_metadata: PaginationMetadata diff --git a/src/orb/types/metric_fetch_response.py b/src/orb/types/metric_fetch_response.py deleted file mode 100644 index 46ecd37f..00000000 --- a/src/orb/types/metric_fetch_response.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from typing_extensions import Literal - -from .item import Item -from .._models import BaseModel - -__all__ = ["MetricFetchResponse"] - - -class MetricFetchResponse(BaseModel): - id: str - - description: Optional[str] = None - - item: Item - """The Item resource represents a sellable product or good. - - Items are associated with all line items, billable metrics, and prices and are - used for defining external sync behavior for invoices and tax calculation - purposes. - """ - - 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`. - """ - - name: str - - status: Literal["active", "draft", "archived"] diff --git a/src/orb/types/metric_list_response.py b/src/orb/types/metric_list_response.py deleted file mode 100644 index ca4bcf79..00000000 --- a/src/orb/types/metric_list_response.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from typing_extensions import Literal - -from .item import Item -from .._models import BaseModel - -__all__ = ["MetricListResponse"] - - -class MetricListResponse(BaseModel): - id: str - - description: Optional[str] = None - - item: Item - """The Item resource represents a sellable product or good. - - Items are associated with all line items, billable metrics, and prices and are - used for defining external sync behavior for invoices and tax calculation - purposes. - """ - - 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`. - """ - - name: str - - status: Literal["active", "draft", "archived"] diff --git a/src/orb/types/metric_update_params.py b/src/orb/types/metric_update_params.py new file mode 100644 index 00000000..5c182e03 --- /dev/null +++ b/src/orb/types/metric_update_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import TypedDict + +__all__ = ["MetricUpdateParams"] + + +class MetricUpdateParams(TypedDict, total=False): + 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`. + """ diff --git a/src/orb/types/mutated_subscription.py b/src/orb/types/mutated_subscription.py new file mode 100644 index 00000000..68183172 --- /dev/null +++ b/src/orb/types/mutated_subscription.py @@ -0,0 +1,259 @@ +# 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 .._utils import PropertyInfo +from .._models import BaseModel +from .customer import Customer +from .shared.price_interval import PriceInterval +from .shared.maximum_interval import MaximumInterval +from .shared.minimum_interval import MinimumInterval +from .shared.coupon_redemption import CouponRedemption +from .shared.adjustment_interval import AdjustmentInterval +from .shared.subscription_trial_info import SubscriptionTrialInfo +from .shared.usage_discount_interval import UsageDiscountInterval +from .shared.amount_discount_interval import AmountDiscountInterval +from .shared.percentage_discount_interval import PercentageDiscountInterval +from .shared.subscription_change_minified import SubscriptionChangeMinified +from .shared.changed_subscription_resources import ChangedSubscriptionResources +from .shared.fixed_fee_quantity_schedule_entry import FixedFeeQuantityScheduleEntry +from .shared.billing_cycle_anchor_configuration import BillingCycleAnchorConfiguration + +__all__ = [ + "MutatedSubscription", + "DiscountInterval", + "DiscountIntervalTieredPercentageDiscountInterval", + "DiscountIntervalTieredPercentageDiscountIntervalFilter", + "DiscountIntervalTieredPercentageDiscountIntervalTier", +] + + +class DiscountIntervalTieredPercentageDiscountIntervalFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class DiscountIntervalTieredPercentageDiscountIntervalTier(BaseModel): + """One band of a tiered percentage discount. + + Bounds are denominated in the discount's currency. + `lower_bound` is the exclusive start of the band and `upper_bound` is the inclusive end; + `upper_bound` is null only for the open-ended final tier. + """ + + lower_bound: float + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: float + """ + The percentage (between 0 and 1) discounted from spend that falls within this + tier. + """ + + upper_bound: Optional[float] = None + """ + Inclusive upper bound of cumulative spend for this tier; null for the final + open-ended tier. + """ + + +class DiscountIntervalTieredPercentageDiscountInterval(BaseModel): + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["tiered_percentage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + filters: List[DiscountIntervalTieredPercentageDiscountIntervalFilter] + """The filters that determine which prices this discount interval applies to.""" + + start_date: datetime + """The start date of the discount interval.""" + + tiers: List[DiscountIntervalTieredPercentageDiscountIntervalTier] + """Only available if discount_type is `tiered_percentage`. + + The ordered, contiguous bands of cumulative eligible spend, each discounted at + its own percentage. + """ + + +DiscountInterval: TypeAlias = Annotated[ + Union[ + AmountDiscountInterval, + PercentageDiscountInterval, + UsageDiscountInterval, + DiscountIntervalTieredPercentageDiscountInterval, + ], + PropertyInfo(discriminator="discount_type"), +] + + +class MutatedSubscription(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 sorted by the start_date of the + adjustment interval. + """ + + 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. + """ + + auto_issuance: Optional[bool] = None + """Determines whether invoices for this subscription will be automatically issued. + + This resolves the effective setting for the subscription: a subscription-level + override if set, otherwise the customer-level setting, otherwise the + account-level default. + """ + + 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](/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](/essentials/timezones) 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 sorted by the start_date. + + This field is deprecated in favor of `adjustment_intervals`. + """ + + end_date: Optional[datetime] = None + """The date Orb stops billing for this subscription.""" + + fixed_fee_quantity_schedule: List[FixedFeeQuantityScheduleEntry] + + invoicing_threshold: Optional[str] = None + + maximum_intervals: List[MaximumInterval] + """The maximum intervals for this subscription sorted by the start_date. + + This field is deprecated in favor of `adjustment_intervals`. + """ + + 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 sorted by the start_date. + + This field is deprecated in favor of `adjustment_intervals`. + """ + + name: str + """The name of the 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. + """ + + pending_subscription_change: Optional[SubscriptionChangeMinified] = None + """A pending subscription change if one exists on this subscription.""" + + plan: Optional[Plan] = None + """ + The [Plan](/core-concepts#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[CouponRedemption] = None + + start_date: datetime + """The date Orb starts billing for this subscription.""" + + status: Literal["active", "ended", "upcoming"] + + trial_info: SubscriptionTrialInfo + + changed_resources: Optional[ChangedSubscriptionResources] = None + """The resources that were changed as part of this operation. + + Only present when fetched through the subscription changes API or if the + `include_changed_resources` parameter was passed in the request. + """ diff --git a/src/orb/types/new_accounting_sync_configuration_param.py b/src/orb/types/new_accounting_sync_configuration_param.py new file mode 100644 index 00000000..0804ac38 --- /dev/null +++ b/src/orb/types/new_accounting_sync_configuration_param.py @@ -0,0 +1,16 @@ +# 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 TypedDict + +from .accounting_provider_config_param import AccountingProviderConfigParam + +__all__ = ["NewAccountingSyncConfigurationParam"] + + +class NewAccountingSyncConfigurationParam(TypedDict, total=False): + accounting_providers: Optional[Iterable[AccountingProviderConfigParam]] + + excluded: Optional[bool] diff --git a/src/orb/types/new_avalara_tax_configuration_param.py b/src/orb/types/new_avalara_tax_configuration_param.py new file mode 100644 index 00000000..14bd2994 --- /dev/null +++ b/src/orb/types/new_avalara_tax_configuration_param.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 Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["NewAvalaraTaxConfigurationParam"] + + +class NewAvalaraTaxConfigurationParam(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["avalara"]] + + automatic_tax_enabled: Optional[bool] + """Whether to automatically calculate tax for this customer. + + When null, inherits from account-level setting. When true or false, overrides + the account setting. + """ + + tax_exemption_code: Optional[str] diff --git a/src/orb/types/new_reporting_configuration_param.py b/src/orb/types/new_reporting_configuration_param.py new file mode 100644 index 00000000..d78c411a --- /dev/null +++ b/src/orb/types/new_reporting_configuration_param.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["NewReportingConfigurationParam"] + + +class NewReportingConfigurationParam(TypedDict, total=False): + exempt: Required[bool] diff --git a/src/orb/types/new_sphere_configuration_param.py b/src/orb/types/new_sphere_configuration_param.py new file mode 100644 index 00000000..ca4050d0 --- /dev/null +++ b/src/orb/types/new_sphere_configuration_param.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["NewSphereConfigurationParam"] + + +class NewSphereConfigurationParam(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["sphere"]] + + automatic_tax_enabled: Optional[bool] + """Whether to automatically calculate tax for this customer. + + When null, inherits from account-level setting. When true or false, overrides + the account setting. + """ diff --git a/src/orb/types/new_subscription_bulk_price_param.py b/src/orb/types/new_subscription_bulk_price_param.py new file mode 100644 index 00000000..7183b603 --- /dev/null +++ b/src/orb/types/new_subscription_bulk_price_param.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.bulk_config import BulkConfig +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewSubscriptionBulkPriceParam", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionBulkPriceParam(TypedDict, total=False): + bulk_config: Required[BulkConfig] + """Configuration for bulk pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_bulk_with_proration_price_param.py b/src/orb/types/new_subscription_bulk_with_proration_price_param.py new file mode 100644 index 00000000..12b1cc4b --- /dev/null +++ b/src/orb/types/new_subscription_bulk_with_proration_price_param.py @@ -0,0 +1,122 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewSubscriptionBulkWithProrationPriceParam", + "BulkWithProrationConfig", + "BulkWithProrationConfigTier", + "ConversionRateConfig", +] + + +class BulkWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier with proration""" + + unit_amount: Required[str] + """Cost per unit""" + + tier_lower_bound: Optional[str] + """The lower bound for this tier""" + + +class BulkWithProrationConfig(TypedDict, total=False): + """Configuration for bulk_with_proration pricing""" + + tiers: Required[Iterable[BulkWithProrationConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionBulkWithProrationPriceParam(TypedDict, total=False): + bulk_with_proration_config: Required[BulkWithProrationConfig] + """Configuration for bulk_with_proration pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk_with_proration"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_cumulative_grouped_bulk_price_param.py b/src/orb/types/new_subscription_cumulative_grouped_bulk_price_param.py new file mode 100644 index 00000000..8f37365c --- /dev/null +++ b/src/orb/types/new_subscription_cumulative_grouped_bulk_price_param.py @@ -0,0 +1,127 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewSubscriptionCumulativeGroupedBulkPriceParam", + "CumulativeGroupedBulkConfig", + "CumulativeGroupedBulkConfigDimensionValue", + "ConversionRateConfig", +] + + +class CumulativeGroupedBulkConfigDimensionValue(TypedDict, total=False): + """Configuration for a dimension value entry""" + + grouping_key: Required[str] + """Grouping key value""" + + tier_lower_bound: Required[str] + """Tier lower bound""" + + unit_amount: Required[str] + """Unit amount for this combination""" + + +class CumulativeGroupedBulkConfig(TypedDict, total=False): + """Configuration for cumulative_grouped_bulk pricing""" + + dimension_values: Required[Iterable[CumulativeGroupedBulkConfigDimensionValue]] + """Each tier lower bound must have the same group of values.""" + + group: Required[str] + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionCumulativeGroupedBulkPriceParam(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_bulk_config: Required[CumulativeGroupedBulkConfig] + """Configuration for cumulative_grouped_bulk pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_bulk"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_grouped_allocation_price_param.py b/src/orb/types/new_subscription_grouped_allocation_price_param.py new file mode 100644 index 00000000..c1ff296d --- /dev/null +++ b/src/orb/types/new_subscription_grouped_allocation_price_param.py @@ -0,0 +1,113 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewSubscriptionGroupedAllocationPriceParam", "GroupedAllocationConfig", "ConversionRateConfig"] + + +class GroupedAllocationConfig(TypedDict, total=False): + """Configuration for grouped_allocation pricing""" + + allocation: Required[str] + """Usage allocation per group""" + + grouping_key: Required[str] + """How to determine the groups that should each be allocated some quantity""" + + overage_unit_rate: Required[str] + """Unit rate for post-allocation""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionGroupedAllocationPriceParam(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[GroupedAllocationConfig] + """Configuration for grouped_allocation pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_grouped_tiered_package_price_param.py b/src/orb/types/new_subscription_grouped_tiered_package_price_param.py new file mode 100644 index 00000000..c5421ac1 --- /dev/null +++ b/src/orb/types/new_subscription_grouped_tiered_package_price_param.py @@ -0,0 +1,129 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewSubscriptionGroupedTieredPackagePriceParam", + "GroupedTieredPackageConfig", + "GroupedTieredPackageConfigTier", + "ConversionRateConfig", +] + + +class GroupedTieredPackageConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + per_unit: Required[str] + """Per package""" + + tier_lower_bound: Required[str] + + +class GroupedTieredPackageConfig(TypedDict, total=False): + """Configuration for grouped_tiered_package pricing""" + + grouping_key: Required[str] + """The event property used to group before tiering""" + + package_size: Required[str] + + tiers: Required[Iterable[GroupedTieredPackageConfigTier]] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionGroupedTieredPackagePriceParam(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_tiered_package_config: Required[GroupedTieredPackageConfig] + """Configuration for grouped_tiered_package pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_tiered_package"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_grouped_tiered_price_param.py b/src/orb/types/new_subscription_grouped_tiered_price_param.py new file mode 100644 index 00000000..1b7e7376 --- /dev/null +++ b/src/orb/types/new_subscription_grouped_tiered_price_param.py @@ -0,0 +1,127 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewSubscriptionGroupedTieredPriceParam", + "GroupedTieredConfig", + "GroupedTieredConfigTier", + "ConversionRateConfig", +] + + +class GroupedTieredConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + tier_lower_bound: Required[str] + + unit_amount: Required[str] + """Per unit amount""" + + +class GroupedTieredConfig(TypedDict, total=False): + """Configuration for grouped_tiered pricing""" + + grouping_key: Required[str] + """The billable metric property used to group before tiering""" + + tiers: Required[Iterable[GroupedTieredConfigTier]] + """ + Apply tiered pricing to each segment generated after grouping with the provided + key + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionGroupedTieredPriceParam(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_tiered_config: Required[GroupedTieredConfig] + """Configuration for grouped_tiered pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_tiered"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_grouped_with_metered_minimum_price_param.py b/src/orb/types/new_subscription_grouped_with_metered_minimum_price_param.py new file mode 100644 index 00000000..21e60430 --- /dev/null +++ b/src/orb/types/new_subscription_grouped_with_metered_minimum_price_param.py @@ -0,0 +1,151 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewSubscriptionGroupedWithMeteredMinimumPriceParam", + "GroupedWithMeteredMinimumConfig", + "GroupedWithMeteredMinimumConfigScalingFactor", + "GroupedWithMeteredMinimumConfigUnitAmount", + "ConversionRateConfig", +] + + +class GroupedWithMeteredMinimumConfigScalingFactor(TypedDict, total=False): + """Configuration for a scaling factor""" + + scaling_factor: Required[str] + + scaling_value: Required[str] + + +class GroupedWithMeteredMinimumConfigUnitAmount(TypedDict, total=False): + """Configuration for a unit amount""" + + pricing_value: Required[str] + + unit_amount: Required[str] + """Per unit amount""" + + +class GroupedWithMeteredMinimumConfig(TypedDict, total=False): + """Configuration for grouped_with_metered_minimum pricing""" + + grouping_key: Required[str] + """Used to partition the usage into groups. + + The minimum amount is applied to each group. + """ + + minimum_unit_amount: Required[str] + """The minimum amount to charge per group per unit""" + + pricing_key: Required[str] + """Used to determine the unit rate""" + + scaling_factors: Required[Iterable[GroupedWithMeteredMinimumConfigScalingFactor]] + """Scale the unit rates by the scaling factor.""" + + scaling_key: Required[str] + """Used to determine the unit rate scaling factor""" + + unit_amounts: Required[Iterable[GroupedWithMeteredMinimumConfigUnitAmount]] + """Apply per unit pricing to each pricing value. + + The minimum amount is applied any unmatched usage. + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionGroupedWithMeteredMinimumPriceParam(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[GroupedWithMeteredMinimumConfig] + """Configuration for grouped_with_metered_minimum pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_metered_minimum"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_grouped_with_prorated_minimum_price_param.py b/src/orb/types/new_subscription_grouped_with_prorated_minimum_price_param.py new file mode 100644 index 00000000..533f193e --- /dev/null +++ b/src/orb/types/new_subscription_grouped_with_prorated_minimum_price_param.py @@ -0,0 +1,117 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewSubscriptionGroupedWithProratedMinimumPriceParam", + "GroupedWithProratedMinimumConfig", + "ConversionRateConfig", +] + + +class GroupedWithProratedMinimumConfig(TypedDict, total=False): + """Configuration for grouped_with_prorated_minimum pricing""" + + grouping_key: Required[str] + """How to determine the groups that should each have a minimum""" + + minimum: Required[str] + """The minimum amount to charge per group""" + + unit_rate: Required[str] + """The amount to charge per unit""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionGroupedWithProratedMinimumPriceParam(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[GroupedWithProratedMinimumConfig] + """Configuration for grouped_with_prorated_minimum pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_prorated_minimum"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_matrix_price_param.py b/src/orb/types/new_subscription_matrix_price_param.py new file mode 100644 index 00000000..09b1d87d --- /dev/null +++ b/src/orb/types/new_subscription_matrix_price_param.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.matrix_config import MatrixConfig +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewSubscriptionMatrixPriceParam", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionMatrixPriceParam(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 price will be associated with.""" + + matrix_config: Required[MatrixConfig] + """Configuration for matrix pricing""" + + model_type: Required[Literal["matrix"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_matrix_with_allocation_price_param.py b/src/orb/types/new_subscription_matrix_with_allocation_price_param.py new file mode 100644 index 00000000..3c3bc127 --- /dev/null +++ b/src/orb/types/new_subscription_matrix_with_allocation_price_param.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.matrix_with_allocation_config import MatrixWithAllocationConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewSubscriptionMatrixWithAllocationPriceParam", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionMatrixWithAllocationPriceParam(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 price will be associated with.""" + + matrix_with_allocation_config: Required[MatrixWithAllocationConfig] + """Configuration for matrix_with_allocation pricing""" + + model_type: Required[Literal["matrix_with_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_matrix_with_display_name_price_param.py b/src/orb/types/new_subscription_matrix_with_display_name_price_param.py new file mode 100644 index 00000000..8d076d3d --- /dev/null +++ b/src/orb/types/new_subscription_matrix_with_display_name_price_param.py @@ -0,0 +1,128 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewSubscriptionMatrixWithDisplayNamePriceParam", + "MatrixWithDisplayNameConfig", + "MatrixWithDisplayNameConfigUnitAmount", + "ConversionRateConfig", +] + + +class MatrixWithDisplayNameConfigUnitAmount(TypedDict, total=False): + """Configuration for a unit amount item""" + + dimension_value: Required[str] + """The dimension value""" + + display_name: Required[str] + """Display name for this dimension value""" + + unit_amount: Required[str] + """Per unit amount""" + + +class MatrixWithDisplayNameConfig(TypedDict, total=False): + """Configuration for matrix_with_display_name pricing""" + + dimension: Required[str] + """Used to determine the unit rate""" + + unit_amounts: Required[Iterable[MatrixWithDisplayNameConfigUnitAmount]] + """Apply per unit pricing to each dimension value""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionMatrixWithDisplayNamePriceParam(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 price will be associated with.""" + + matrix_with_display_name_config: Required[MatrixWithDisplayNameConfig] + """Configuration for matrix_with_display_name pricing""" + + model_type: Required[Literal["matrix_with_display_name"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_max_group_tiered_package_price_param.py b/src/orb/types/new_subscription_max_group_tiered_package_price_param.py new file mode 100644 index 00000000..9b6048d9 --- /dev/null +++ b/src/orb/types/new_subscription_max_group_tiered_package_price_param.py @@ -0,0 +1,128 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewSubscriptionMaxGroupTieredPackagePriceParam", + "MaxGroupTieredPackageConfig", + "MaxGroupTieredPackageConfigTier", + "ConversionRateConfig", +] + + +class MaxGroupTieredPackageConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + tier_lower_bound: Required[str] + + unit_amount: Required[str] + """Per unit amount""" + + +class MaxGroupTieredPackageConfig(TypedDict, total=False): + """Configuration for max_group_tiered_package pricing""" + + grouping_key: Required[str] + """ + The event property used to group before tiering the group with the highest value + """ + + package_size: Required[str] + + tiers: Required[Iterable[MaxGroupTieredPackageConfigTier]] + """Apply tiered pricing to the largest group after grouping with the provided key.""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionMaxGroupTieredPackagePriceParam(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 price will be associated with.""" + + max_group_tiered_package_config: Required[MaxGroupTieredPackageConfig] + """Configuration for max_group_tiered_package pricing""" + + model_type: Required[Literal["max_group_tiered_package"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_minimum_composite_price_param.py b/src/orb/types/new_subscription_minimum_composite_price_param.py new file mode 100644 index 00000000..dc4df40b --- /dev/null +++ b/src/orb/types/new_subscription_minimum_composite_price_param.py @@ -0,0 +1,110 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewSubscriptionMinimumCompositePriceParam", "MinimumCompositeConfig", "ConversionRateConfig"] + + +class MinimumCompositeConfig(TypedDict, total=False): + """Configuration for minimum_composite pricing""" + + minimum_amount: Required[str] + """The minimum amount to apply""" + + prorated: bool + """If true, subtotals from this price are prorated based on the service period""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionMinimumCompositePriceParam(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 price will be associated with.""" + + minimum_composite_config: Required[MinimumCompositeConfig] + """Configuration for minimum_composite pricing""" + + model_type: Required[Literal["minimum_composite"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_package_price_param.py b/src/orb/types/new_subscription_package_price_param.py new file mode 100644 index 00000000..bf9317ad --- /dev/null +++ b/src/orb/types/new_subscription_package_price_param.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.package_config import PackageConfig +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewSubscriptionPackagePriceParam", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionPackagePriceParam(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 price will be associated with.""" + + model_type: Required[Literal["package"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + package_config: Required[PackageConfig] + """Configuration for package pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_package_with_allocation_price_param.py b/src/orb/types/new_subscription_package_with_allocation_price_param.py new file mode 100644 index 00000000..cc38d26d --- /dev/null +++ b/src/orb/types/new_subscription_package_with_allocation_price_param.py @@ -0,0 +1,110 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewSubscriptionPackageWithAllocationPriceParam", "PackageWithAllocationConfig", "ConversionRateConfig"] + + +class PackageWithAllocationConfig(TypedDict, total=False): + """Configuration for package_with_allocation pricing""" + + allocation: Required[str] + + package_amount: Required[str] + + package_size: Required[str] + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionPackageWithAllocationPriceParam(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 price will be associated with.""" + + model_type: Required[Literal["package_with_allocation"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + package_with_allocation_config: Required[PackageWithAllocationConfig] + """Configuration for package_with_allocation pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_scalable_matrix_with_tiered_pricing_price_param.py b/src/orb/types/new_subscription_scalable_matrix_with_tiered_pricing_price_param.py new file mode 100644 index 00000000..cd462766 --- /dev/null +++ b/src/orb/types/new_subscription_scalable_matrix_with_tiered_pricing_price_param.py @@ -0,0 +1,139 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewSubscriptionScalableMatrixWithTieredPricingPriceParam", + "ScalableMatrixWithTieredPricingConfig", + "ScalableMatrixWithTieredPricingConfigMatrixScalingFactor", + "ScalableMatrixWithTieredPricingConfigTier", + "ConversionRateConfig", +] + + +class ScalableMatrixWithTieredPricingConfigMatrixScalingFactor(TypedDict, total=False): + """Configuration for a single matrix scaling factor""" + + first_dimension_value: Required[str] + + scaling_factor: Required[str] + + second_dimension_value: Optional[str] + + +class ScalableMatrixWithTieredPricingConfigTier(TypedDict, total=False): + """Configuration for a single tier entry with business logic""" + + tier_lower_bound: Required[str] + + unit_amount: Required[str] + + +class ScalableMatrixWithTieredPricingConfig(TypedDict, total=False): + """Configuration for scalable_matrix_with_tiered_pricing pricing""" + + first_dimension: Required[str] + """Used for the scalable matrix first dimension""" + + matrix_scaling_factors: Required[Iterable[ScalableMatrixWithTieredPricingConfigMatrixScalingFactor]] + """Apply a scaling factor to each dimension""" + + tiers: Required[Iterable[ScalableMatrixWithTieredPricingConfigTier]] + + second_dimension: Optional[str] + """Used for the scalable matrix second dimension (optional)""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionScalableMatrixWithTieredPricingPriceParam(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 price will be associated with.""" + + model_type: Required[Literal["scalable_matrix_with_tiered_pricing"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + scalable_matrix_with_tiered_pricing_config: Required[ScalableMatrixWithTieredPricingConfig] + """Configuration for scalable_matrix_with_tiered_pricing pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_scalable_matrix_with_unit_pricing_price_param.py b/src/orb/types/new_subscription_scalable_matrix_with_unit_pricing_price_param.py new file mode 100644 index 00000000..683bf6db --- /dev/null +++ b/src/orb/types/new_subscription_scalable_matrix_with_unit_pricing_price_param.py @@ -0,0 +1,137 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewSubscriptionScalableMatrixWithUnitPricingPriceParam", + "ScalableMatrixWithUnitPricingConfig", + "ScalableMatrixWithUnitPricingConfigMatrixScalingFactor", + "ConversionRateConfig", +] + + +class ScalableMatrixWithUnitPricingConfigMatrixScalingFactor(TypedDict, total=False): + """Configuration for a single matrix scaling factor""" + + first_dimension_value: Required[str] + + scaling_factor: Required[str] + + second_dimension_value: Optional[str] + + +class ScalableMatrixWithUnitPricingConfig(TypedDict, total=False): + """Configuration for scalable_matrix_with_unit_pricing pricing""" + + first_dimension: Required[str] + """Used to determine the unit rate""" + + matrix_scaling_factors: Required[Iterable[ScalableMatrixWithUnitPricingConfigMatrixScalingFactor]] + """Apply a scaling factor to each dimension""" + + unit_price: Required[str] + """The final unit price to rate against the output of the matrix""" + + grouping_key: Optional[str] + """The property used to group this price""" + + prorate: Optional[bool] + """If true, the unit price will be prorated to the billing period""" + + second_dimension: Optional[str] + """Used to determine the unit rate (optional)""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionScalableMatrixWithUnitPricingPriceParam(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 price will be associated with.""" + + model_type: Required[Literal["scalable_matrix_with_unit_pricing"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + scalable_matrix_with_unit_pricing_config: Required[ScalableMatrixWithUnitPricingConfig] + """Configuration for scalable_matrix_with_unit_pricing pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_threshold_total_amount_price_param.py b/src/orb/types/new_subscription_threshold_total_amount_price_param.py new file mode 100644 index 00000000..1345b770 --- /dev/null +++ b/src/orb/types/new_subscription_threshold_total_amount_price_param.py @@ -0,0 +1,127 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewSubscriptionThresholdTotalAmountPriceParam", + "ThresholdTotalAmountConfig", + "ThresholdTotalAmountConfigConsumptionTable", + "ConversionRateConfig", +] + + +class ThresholdTotalAmountConfigConsumptionTable(TypedDict, total=False): + """Configuration for a single threshold""" + + threshold: Required[str] + + total_amount: Required[str] + """Total amount for this threshold""" + + +class ThresholdTotalAmountConfig(TypedDict, total=False): + """Configuration for threshold_total_amount pricing""" + + consumption_table: Required[Iterable[ThresholdTotalAmountConfigConsumptionTable]] + """ + When the quantity consumed passes a provided threshold, the configured total + will be charged + """ + + prorate: Optional[bool] + """If true, the unit price will be prorated to the billing period""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionThresholdTotalAmountPriceParam(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 price will be associated with.""" + + model_type: Required[Literal["threshold_total_amount"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + threshold_total_amount_config: Required[ThresholdTotalAmountConfig] + """Configuration for threshold_total_amount pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_tiered_package_price_param.py b/src/orb/types/new_subscription_tiered_package_price_param.py new file mode 100644 index 00000000..9a0385a3 --- /dev/null +++ b/src/orb/types/new_subscription_tiered_package_price_param.py @@ -0,0 +1,128 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewSubscriptionTieredPackagePriceParam", + "TieredPackageConfig", + "TieredPackageConfigTier", + "ConversionRateConfig", +] + + +class TieredPackageConfigTier(TypedDict, total=False): + """Configuration for a single tier with business logic""" + + per_unit: Required[str] + """Price per package""" + + tier_lower_bound: Required[str] + + +class TieredPackageConfig(TypedDict, total=False): + """Configuration for tiered_package pricing""" + + package_size: Required[str] + + tiers: Required[Iterable[TieredPackageConfigTier]] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. The tier bounds are defined + based on the total quantity rather than the number of packages, so they must be + multiples of the package size. + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionTieredPackagePriceParam(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 price will be associated with.""" + + model_type: Required[Literal["tiered_package"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_package_config: Required[TieredPackageConfig] + """Configuration for tiered_package pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_tiered_package_with_minimum_price_param.py b/src/orb/types/new_subscription_tiered_package_with_minimum_price_param.py new file mode 100644 index 00000000..9820fa69 --- /dev/null +++ b/src/orb/types/new_subscription_tiered_package_with_minimum_price_param.py @@ -0,0 +1,127 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewSubscriptionTieredPackageWithMinimumPriceParam", + "TieredPackageWithMinimumConfig", + "TieredPackageWithMinimumConfigTier", + "ConversionRateConfig", +] + + +class TieredPackageWithMinimumConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + minimum_amount: Required[str] + + per_unit: Required[str] + + tier_lower_bound: Required[str] + + +class TieredPackageWithMinimumConfig(TypedDict, total=False): + """Configuration for tiered_package_with_minimum pricing""" + + package_size: Required[float] + + tiers: Required[Iterable[TieredPackageWithMinimumConfigTier]] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionTieredPackageWithMinimumPriceParam(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 price will be associated with.""" + + model_type: Required[Literal["tiered_package_with_minimum"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_package_with_minimum_config: Required[TieredPackageWithMinimumConfig] + """Configuration for tiered_package_with_minimum pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_tiered_price_param.py b/src/orb/types/new_subscription_tiered_price_param.py new file mode 100644 index 00000000..77d73687 --- /dev/null +++ b/src/orb/types/new_subscription_tiered_price_param.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.tiered_config import TieredConfig +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewSubscriptionTieredPriceParam", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionTieredPriceParam(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 price will be associated with.""" + + model_type: Required[Literal["tiered"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_config: Required[TieredConfig] + """Configuration for tiered pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_tiered_with_minimum_price_param.py b/src/orb/types/new_subscription_tiered_with_minimum_price_param.py new file mode 100644 index 00000000..2ebcf5e8 --- /dev/null +++ b/src/orb/types/new_subscription_tiered_with_minimum_price_param.py @@ -0,0 +1,132 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewSubscriptionTieredWithMinimumPriceParam", + "TieredWithMinimumConfig", + "TieredWithMinimumConfigTier", + "ConversionRateConfig", +] + + +class TieredWithMinimumConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + minimum_amount: Required[str] + + tier_lower_bound: Required[str] + + unit_amount: Required[str] + """Per unit amount""" + + +class TieredWithMinimumConfig(TypedDict, total=False): + """Configuration for tiered_with_minimum pricing""" + + tiers: Required[Iterable[TieredWithMinimumConfigTier]] + """Tiered pricing with a minimum amount dependent on the volume tier. + + Tiers are defined using exclusive lower bounds. + """ + + hide_zero_amount_tiers: bool + """If true, tiers with an accrued amount of 0 will not be included in the rating.""" + + prorate: bool + """If true, the unit price will be prorated to the billing period""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionTieredWithMinimumPriceParam(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 price will be associated with.""" + + model_type: Required[Literal["tiered_with_minimum"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_with_minimum_config: Required[TieredWithMinimumConfig] + """Configuration for tiered_with_minimum pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_unit_price_param.py b/src/orb/types/new_subscription_unit_price_param.py new file mode 100644 index 00000000..1259881b --- /dev/null +++ b/src/orb/types/new_subscription_unit_price_param.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_config import UnitConfig +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewSubscriptionUnitPriceParam", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionUnitPriceParam(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 price will be associated with.""" + + model_type: Required[Literal["unit"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_config: Required[UnitConfig] + """Configuration for unit pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_unit_with_percent_price_param.py b/src/orb/types/new_subscription_unit_with_percent_price_param.py new file mode 100644 index 00000000..254ede68 --- /dev/null +++ b/src/orb/types/new_subscription_unit_with_percent_price_param.py @@ -0,0 +1,110 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewSubscriptionUnitWithPercentPriceParam", "UnitWithPercentConfig", "ConversionRateConfig"] + + +class UnitWithPercentConfig(TypedDict, total=False): + """Configuration for unit_with_percent pricing""" + + percent: Required[str] + """What percent, out of 100, of the calculated total to charge""" + + unit_amount: Required[str] + """Rate per unit of usage""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionUnitWithPercentPriceParam(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 price will be associated with.""" + + model_type: Required[Literal["unit_with_percent"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_with_percent_config: Required[UnitWithPercentConfig] + """Configuration for unit_with_percent pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_subscription_unit_with_proration_price_param.py b/src/orb/types/new_subscription_unit_with_proration_price_param.py new file mode 100644 index 00000000..55d08831 --- /dev/null +++ b/src/orb/types/new_subscription_unit_with_proration_price_param.py @@ -0,0 +1,107 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewSubscriptionUnitWithProrationPriceParam", "UnitWithProrationConfig", "ConversionRateConfig"] + + +class UnitWithProrationConfig(TypedDict, total=False): + """Configuration for unit_with_proration pricing""" + + unit_amount: Required[str] + """Rate per unit of usage""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewSubscriptionUnitWithProrationPriceParam(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 price will be associated with.""" + + model_type: Required[Literal["unit_with_proration"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_with_proration_config: Required[UnitWithProrationConfig] + """Configuration for unit_with_proration pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/new_tax_jar_configuration_param.py b/src/orb/types/new_tax_jar_configuration_param.py new file mode 100644 index 00000000..bf1849bc --- /dev/null +++ b/src/orb/types/new_tax_jar_configuration_param.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["NewTaxJarConfigurationParam"] + + +class NewTaxJarConfigurationParam(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["taxjar"]] + + automatic_tax_enabled: Optional[bool] + """Whether to automatically calculate tax for this customer. + + When null, inherits from account-level setting. When true or false, overrides + the account setting. + """ diff --git a/src/orb/types/plan.py b/src/orb/types/plan.py index 1e884bc8..96fceff4 100644 --- a/src/orb/types/plan.py +++ b/src/orb/types/plan.py @@ -1,81 +1,135 @@ # 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 .shared import Discount +from .._utils import PropertyInfo from .._models import BaseModel +from .shared.price import Price +from .shared.maximum import Maximum +from .shared.minimum import Minimum +from .shared.discount import Discount +from .shared.plan_phase_maximum_adjustment import PlanPhaseMaximumAdjustment +from .shared.plan_phase_minimum_adjustment import PlanPhaseMinimumAdjustment +from .shared.plan_phase_usage_discount_adjustment import PlanPhaseUsageDiscountAdjustment +from .shared.plan_phase_amount_discount_adjustment import PlanPhaseAmountDiscountAdjustment +from .shared.plan_phase_percentage_discount_adjustment import PlanPhasePercentageDiscountAdjustment __all__ = [ "Plan", + "Adjustment", + "AdjustmentPlanPhaseTieredPercentageDiscountAdjustment", + "AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentFilter", + "AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentTier", "BasePlan", - "Maximum", - "Minimum", "PlanPhase", - "PlanPhaseMaximum", - "PlanPhaseMinimum", "Product", "TrialConfig", ] -class BasePlan(BaseModel): - id: Optional[str] = None +class AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" - external_plan_id: Optional[str] = None - """ - An optional user-defined ID for this plan resource, used throughout the system - as an alias for this Plan. Use this field to identify a plan by an existing - identifier in your system. - """ + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" - name: Optional[str] = None + values: List[str] + """The IDs or values that match this filter.""" -class Maximum(BaseModel): - applies_to_price_ids: List[str] - """List of price_ids that this maximum amount applies to. +class AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentTier(BaseModel): + """One band of a tiered percentage discount. - For plan/plan phase maximums, this can be a subset of prices. + Bounds are denominated in the discount's currency. + `lower_bound` is the exclusive start of the band and `upper_bound` is the inclusive end; + `upper_bound` is null only for the open-ended final tier. """ - maximum_amount: str - """Maximum amount applied""" + lower_bound: float + """Exclusive lower bound of cumulative spend for this tier.""" + percentage: float + """ + The percentage (between 0 and 1) discounted from spend that falls within this + tier. + """ + + upper_bound: Optional[float] = None + """ + Inclusive upper bound of cumulative spend for this tier; null for the final + open-ended tier. + """ + + +class AdjustmentPlanPhaseTieredPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["tiered_percentage_discount"] -class Minimum(BaseModel): applies_to_price_ids: List[str] - """List of price_ids that this minimum amount applies to. + """The price IDs that this adjustment applies to.""" - For plan/plan phase minimums, this can be a subset of prices. + filters: List[AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentFilter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, false for adjustments that + apply to only one price. """ - minimum_amount: str - """Minimum amount applied""" + 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 PlanPhaseMaximum(BaseModel): - applies_to_price_ids: List[str] - """List of price_ids that this maximum amount applies to. + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. - For plan/plan phase maximums, this can be a subset of prices. + This adjustment will take the place of the replaced adjustment in plan version + migrations. """ - maximum_amount: str - """Maximum amount applied""" + tiers: List[AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentTier] + """ + The ordered, contiguous bands of cumulative eligible spend, each discounted at + its own percentage (progressive fill-a-tier), applied to the prices this + adjustment covers in a given billing period. + """ -class PlanPhaseMinimum(BaseModel): - applies_to_price_ids: List[str] - """List of price_ids that this minimum amount applies to. +Adjustment: TypeAlias = Annotated[ + Union[ + PlanPhaseUsageDiscountAdjustment, + PlanPhaseAmountDiscountAdjustment, + PlanPhasePercentageDiscountAdjustment, + AdjustmentPlanPhaseTieredPercentageDiscountAdjustment, + PlanPhaseMinimumAdjustment, + PlanPhaseMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + + +class BasePlan(BaseModel): + """ + Legacy field representing the parent plan if the current plan is a 'child plan', overriding prices from the parent. + """ - For plan/plan phase minimums, this can be a subset of prices. + id: Optional[str] = None + + external_plan_id: Optional[str] = None + """ + An optional user-defined ID for this plan resource, used throughout the system + as an alias for this Plan. Use this field to identify a plan by an existing + identifier in your system. """ - minimum_amount: str - """Minimum amount applied""" + name: Optional[str] = None class PlanPhase(BaseModel): @@ -91,13 +145,13 @@ class PlanPhase(BaseModel): If null, this phase is evergreen and active indefinitely """ - duration_unit: Optional[Literal["daily", "monthly", "quarterly", "annual"]] = None + duration_unit: Optional[Literal["daily", "monthly", "quarterly", "semi_annual", "annual"]] = None - maximum: Optional[PlanPhaseMaximum] = None + maximum: Optional[Maximum] = None maximum_amount: Optional[str] = None - minimum: Optional[PlanPhaseMinimum] = None + minimum: Optional[Minimum] = None minimum_amount: Optional[str] = None @@ -122,14 +176,30 @@ class TrialConfig(BaseModel): class Plan(BaseModel): + """ + The [Plan](/core-concepts#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). + """ + 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 + """ + Legacy field representing the parent plan if the current plan is a 'child plan', + overriding prices from the parent. + """ base_plan_id: Optional[str] = None """ - The parent plan id if the given plan was created by overriding one or more of - the parent's prices + Legacy field representing the parent plan ID if the current plan is a 'child + plan', overriding prices from the parent. """ created_at: datetime diff --git a/src/orb/types/plan_create_params.py b/src/orb/types/plan_create_params.py index be18abae..ea37466d 100644 --- a/src/orb/types/plan_create_params.py +++ b/src/orb/types/plan_create_params.py @@ -2,38 +2,95 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .shared_params.new_maximum import NewMaximum +from .shared_params.new_minimum import NewMinimum +from .shared_params.unit_config import UnitConfig +from .shared_params.new_usage_discount import NewUsageDiscount +from .shared_params.new_amount_discount import NewAmountDiscount +from .shared_params.new_plan_bulk_price import NewPlanBulkPrice +from .shared_params.new_plan_unit_price import NewPlanUnitPrice +from .shared_params.new_allocation_price import NewAllocationPrice +from .shared_params.new_plan_matrix_price import NewPlanMatrixPrice +from .shared_params.new_plan_tiered_price import NewPlanTieredPrice +from .shared_params.new_plan_package_price import NewPlanPackagePrice +from .shared_params.new_percentage_discount import NewPercentageDiscount +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.new_plan_grouped_tiered_price import NewPlanGroupedTieredPrice +from .shared_params.new_plan_tiered_package_price import NewPlanTieredPackagePrice +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_plan_minimum_composite_price import NewPlanMinimumCompositePrice +from .shared_params.new_plan_unit_with_percent_price import NewPlanUnitWithPercentPrice +from .shared_params.new_plan_grouped_allocation_price import NewPlanGroupedAllocationPrice +from .shared_params.new_plan_bulk_with_proration_price import NewPlanBulkWithProrationPrice +from .shared_params.new_plan_tiered_with_minimum_price import NewPlanTieredWithMinimumPrice +from .shared_params.new_plan_unit_with_proration_price import NewPlanUnitWithProrationPrice +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration +from .shared_params.new_plan_grouped_tiered_package_price import NewPlanGroupedTieredPackagePrice +from .shared_params.new_plan_matrix_with_allocation_price import NewPlanMatrixWithAllocationPrice +from .shared_params.new_plan_threshold_total_amount_price import NewPlanThresholdTotalAmountPrice +from .shared_params.new_plan_cumulative_grouped_bulk_price import NewPlanCumulativeGroupedBulkPrice +from .shared_params.new_plan_package_with_allocation_price import NewPlanPackageWithAllocationPrice +from .shared_params.new_plan_matrix_with_display_name_price import NewPlanMatrixWithDisplayNamePrice +from .shared_params.new_plan_max_group_tiered_package_price import NewPlanMaxGroupTieredPackagePrice +from .shared_params.new_plan_tiered_package_with_minimum_price import NewPlanTieredPackageWithMinimumPrice +from .shared_params.new_plan_grouped_with_metered_minimum_price import NewPlanGroupedWithMeteredMinimumPrice +from .shared_params.new_plan_grouped_with_prorated_minimum_price import NewPlanGroupedWithProratedMinimumPrice +from .shared_params.new_plan_scalable_matrix_with_unit_pricing_price import NewPlanScalableMatrixWithUnitPricingPrice +from .shared_params.new_plan_scalable_matrix_with_tiered_pricing_price import ( + NewPlanScalableMatrixWithTieredPricingPrice, +) __all__ = [ "PlanCreateParams", "Price", - "PriceNewPlanUnitPrice", - "PriceNewPlanUnitPriceUnitConfig", - "PriceNewPlanPackagePrice", - "PriceNewPlanPackagePricePackageConfig", - "PriceNewPlanMatrixPrice", - "PriceNewPlanMatrixPriceMatrixConfig", - "PriceNewPlanMatrixPriceMatrixConfigMatrixValue", - "PriceNewPlanTieredPrice", - "PriceNewPlanTieredPriceTieredConfig", - "PriceNewPlanTieredPriceTieredConfigTier", - "PriceNewPlanTieredBpsPrice", - "PriceNewPlanTieredBpsPriceTieredBpsConfig", - "PriceNewPlanTieredBpsPriceTieredBpsConfigTier", - "PriceNewPlanBpsPrice", - "PriceNewPlanBpsPriceBpsConfig", - "PriceNewPlanBulkBpsPrice", - "PriceNewPlanBulkBpsPriceBulkBpsConfig", - "PriceNewPlanBulkBpsPriceBulkBpsConfigTier", - "PriceNewPlanBulkPrice", - "PriceNewPlanBulkPriceBulkConfig", - "PriceNewPlanBulkPriceBulkConfigTier", - "PriceNewPlanThresholdTotalAmountPrice", - "PriceNewPlanTieredPackagePrice", - "PriceNewPlanTieredWithMinimumPrice", - "PriceNewPlanUnitWithPercentPrice", - "PriceNewPlanPackageWithAllocationPrice", + "PriceLicenseAllocationPrice", + "PriceLicenseAllocationPriceLicenseAllocation", + "PriceLicenseAllocationPriceConversionRateConfig", + "PricePrice", + "PricePriceNewPlanBulkWithFiltersPrice", + "PricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig", + "PricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter", + "PricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier", + "PricePriceNewPlanBulkWithFiltersPriceConversionRateConfig", + "PricePriceNewPlanMatrixWithThresholdDiscountsPrice", + "PricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig", + "PricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue", + "PricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup", + "PricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig", + "PricePriceNewPlanTieredWithProrationPrice", + "PricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig", + "PricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier", + "PricePriceNewPlanTieredWithProrationPriceConversionRateConfig", + "PricePriceNewPlanGroupedWithMinMaxThresholdsPrice", + "PricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig", + "PricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig", + "PricePriceNewPlanCumulativeGroupedAllocationPrice", + "PricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig", + "PricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig", + "PricePriceNewPlanDailyCreditAllowancePrice", + "PricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig", + "PricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue", + "PricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig", + "PricePriceNewPlanMeteredAllowancePrice", + "PricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig", + "PricePriceNewPlanMeteredAllowancePriceConversionRateConfig", + "PricePriceNewPlanPercentCompositePrice", + "PricePriceNewPlanPercentCompositePricePercentConfig", + "PricePriceNewPlanPercentCompositePriceConversionRateConfig", + "PricePriceNewPlanEventOutputPrice", + "PricePriceNewPlanEventOutputPriceEventOutputConfig", + "PricePriceNewPlanEventOutputPriceConversionRateConfig", + "Adjustment", + "AdjustmentAdjustment", + "AdjustmentAdjustmentNewTieredPercentageDiscount", + "AdjustmentAdjustmentNewTieredPercentageDiscountTier", + "AdjustmentAdjustmentNewTieredPercentageDiscountFilter", + "PlanPhase", ] @@ -52,11 +109,20 @@ class PlanCreateParams(TypedDict, total=False): If the plan has phases, this includes prices across all phases of the plan. """ + adjustments: Optional[Iterable[Adjustment]] + """Adjustments for this plan. + + If the plan has phases, this includes adjustments across all phases of the plan. + """ + default_invoice_memo: Optional[str] """ Free-form text which is available on the invoice PDF and the Orb invoice portal. """ + description: Optional[str] + """An optional user-defined description of the plan.""" + external_plan_id: Optional[str] metadata: Optional[Dict[str, Optional[str]]] @@ -73,25 +139,57 @@ class PlanCreateParams(TypedDict, total=False): to 0. """ + plan_phases: Optional[Iterable[PlanPhase]] + """Configuration of pre-defined phases, each with their own prices and adjustments. -class PriceNewPlanUnitPriceUnitConfig(TypedDict, total=False): - unit_amount: Required[str] - """Rate per unit of usage""" + Leave unspecified for plans with a single phase. + """ + + status: Literal["active", "draft"] + """The status of the plan to create (either active or draft). + + If not specified, this defaults to active. + """ + + +class PriceLicenseAllocationPriceLicenseAllocation(TypedDict, total=False): + amount: Required[str] + """The amount of credits granted per active license per cadence.""" + + currency: Required[str] + """The currency of the license allocation.""" + write_off_overage: Optional[bool] + """When True, overage beyond the allocation is written off.""" -class PriceNewPlanUnitPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] + +PriceLicenseAllocationPriceConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class PriceLicenseAllocationPrice(TypedDict, total=False): + """The license allocation price to add to the plan.""" + + 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.""" + """The id of the item the price will be associated with.""" + + license_allocations: Required[Iterable[PriceLicenseAllocationPriceLicenseAllocation]] + """License allocations to associate with this price. + + Each entry defines a per-license credit pool granted each cadence. Requires + license_type_id or license_type_configuration to be set. + """ model_type: Required[Literal["unit"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - unit_config: Required[PriceNewPlanUnitPriceUnitConfig] + unit_config: Required[UnitConfig] + """Configuration for unit pricing""" billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -105,6 +203,27 @@ class PriceNewPlanUnitPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PriceLicenseAllocationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -117,33 +236,80 @@ class PriceNewPlanUnitPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceNewPlanPackagePricePackageConfig(TypedDict, total=False): - package_amount: Required[str] - """A currency amount to rate usage by""" + If unspecified, a single invoice is produced per billing cycle. + """ - package_size: Optional[int] - """An integer amount to represent package size. + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - For example, 1000 here would divide usage by 1000 before multiplying by - package_amount in rating + 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 PriceNewPlanPackagePrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class PricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter(TypedDict, total=False): + """Configuration for a single property filter""" + + property_key: Required[str] + """Event property key to filter on""" + + property_value: Required[str] + """Event property value to match""" + + +class PricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier""" + + unit_amount: Required[str] + """Amount per unit""" + + tier_lower_bound: Optional[str] + """The lower bound for this tier""" + + +class PricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig(TypedDict, total=False): + """Configuration for bulk_with_filters pricing""" + + filters: Required[Iterable[PricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigFilter]] + """Property filters to apply (all must match)""" + + tiers: Required[Iterable[PricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +PricePriceNewPlanBulkWithFiltersPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PricePriceNewPlanBulkWithFiltersPrice(TypedDict, total=False): + bulk_with_filters_config: Required[PricePriceNewPlanBulkWithFiltersPriceBulkWithFiltersConfig] + """Configuration for bulk_with_filters pricing""" + + 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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["package"]] + model_type: Required[Literal["bulk_with_filters"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - package_config: Required[PriceNewPlanPackagePricePackageConfig] - billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -156,6 +322,27 @@ class PriceNewPlanPackagePrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PricePriceNewPlanBulkWithFiltersPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -168,40 +355,104 @@ class PriceNewPlanPackagePrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ -class PriceNewPlanMatrixPriceMatrixConfigMatrixValue(TypedDict, total=False): - dimension_values: Required[List[Optional[str]]] - """One or two matrix keys to filter usage to this Matrix value by. + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - For example, ["region", "tier"] could be used to filter cloud usage by a cloud - region and an instance tier. + 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 PricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue( + TypedDict, total=False +): + first_dimension_value: Required[str] + unit_amount: Required[str] - """Unit price for the specified dimension_values""" + second_dimension_value: Optional[str] + + +class PricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup( + TypedDict, total=False +): + above_threshold_discount_percentage: Required[str] + """Discount rate applied to spend above the threshold.""" + + below_threshold_discount_percentage: Required[str] + """Discount rate applied to spend at or below the threshold. + + Set to 0 for no baseline discount. + """ + + cell_coordinates: Required[str] + """Semicolon-separated list of matrix cell coordinates targeted by this group. + + Each coordinate is `first,second` when the matrix has two dimensions, or just + `first` for a single-dimension matrix. Example: `blue,circle;green,triangle`. + """ + + threshold_amount: Required[str] + + description: Optional[str] + + +class PricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig(TypedDict, total=False): + """Configuration for matrix_with_threshold_discounts pricing""" -class PriceNewPlanMatrixPriceMatrixConfig(TypedDict, total=False): default_unit_amount: Required[str] - """Default per unit rate for any usage not bucketed into a specified matrix_value""" + """Unit price used for usage that does not match any defined matrix cell.""" - dimensions: Required[List[Optional[str]]] - """One or two event property values to evaluate matrix groups by""" + first_dimension: Required[str] + """First matrix dimension key.""" + + matrix_values: Required[ + Iterable[PricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue] + ] + """Per-cell unit prices.""" + + second_dimension: Optional[str] + """Optional second matrix dimension key.""" - matrix_values: Required[Iterable[PriceNewPlanMatrixPriceMatrixConfigMatrixValue]] - """Matrix values for specified matrix grouping keys""" + threshold_discount_groups: Iterable[ + PricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup + ] + + +PricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] -class PriceNewPlanMatrixPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class PricePriceNewPlanMatrixWithThresholdDiscountsPrice(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.""" + """The id of the item the price will be associated with.""" - matrix_config: Required[PriceNewPlanMatrixPriceMatrixConfig] + matrix_with_threshold_discounts_config: Required[ + PricePriceNewPlanMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + ] + """Configuration for matrix_with_threshold_discounts pricing""" - model_type: Required[Literal["matrix"]] + model_type: Required[Literal["matrix_with_threshold_discounts"]] + """The pricing model type""" name: Required[str] """The name of the price.""" @@ -218,6 +469,27 @@ class PriceNewPlanMatrixPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PricePriceNewPlanMatrixWithThresholdDiscountsPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -230,36 +502,69 @@ class PriceNewPlanMatrixPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceNewPlanTieredPriceTieredConfigTier(TypedDict, total=False): - first_unit: Required[float] +class PricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single tiered with proration tier""" + + tier_lower_bound: Required[str] """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 PricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig(TypedDict, total=False): + """Configuration for tiered_with_proration pricing""" -class PriceNewPlanTieredPriceTieredConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceNewPlanTieredPriceTieredConfigTier]] - """Tiers for rating based on total usage quantities into the specified tier""" + tiers: Required[Iterable[PricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfigTier]] + """ + Tiers for rating based on total usage quantities into the specified tier with + proration + """ -class PriceNewPlanTieredPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +PricePriceNewPlanTieredWithProrationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PricePriceNewPlanTieredWithProrationPrice(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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["tiered"]] + model_type: Required[Literal["tiered_with_proration"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - tiered_config: Required[PriceNewPlanTieredPriceTieredConfig] + tiered_with_proration_config: Required[PricePriceNewPlanTieredWithProrationPriceTieredWithProrationConfig] + """Configuration for tiered_with_proration pricing""" billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -273,6 +578,27 @@ class PriceNewPlanTieredPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PricePriceNewPlanTieredWithProrationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -285,43 +611,68 @@ class PriceNewPlanTieredPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceNewPlanTieredBpsPriceTieredBpsConfigTier(TypedDict, total=False): - bps: Required[float] - """Per-event basis point rate""" - - minimum_amount: Required[str] - """Inclusive tier starting value""" + If unspecified, a single invoice is produced per billing cycle. + """ - maximum_amount: Optional[str] - """Exclusive tier ending value""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - per_unit_maximum: Optional[str] - """Per unit maximum to charge""" + 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 PriceNewPlanTieredBpsPriceTieredBpsConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceNewPlanTieredBpsPriceTieredBpsConfigTier]] + reference_id: Optional[str] """ - Tiers for a Graduated BPS pricing model, where usage is bucketed into specified - tiers + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ -class PriceNewPlanTieredBpsPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class PricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig(TypedDict, total=False): + """Configuration for grouped_with_min_max_thresholds pricing""" + + grouping_key: Required[str] + """The event property used to group before applying thresholds""" + + maximum_charge: Required[str] + """The maximum amount to charge each group""" + + minimum_charge: Required[str] + """The minimum amount to charge each group, regardless of usage""" + + per_unit_rate: Required[str] + """The base price charged per group""" + + +PricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PricePriceNewPlanGroupedWithMinMaxThresholdsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] """The cadence to bill for this price on.""" + grouped_with_min_max_thresholds_config: Required[ + PricePriceNewPlanGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + ] + """Configuration for grouped_with_min_max_thresholds pricing""" + item_id: Required[str] - """The id of the item the plan will be associated with.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["tiered_bps"]] + model_type: Required[Literal["grouped_with_min_max_thresholds"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - tiered_bps_config: Required[PriceNewPlanTieredBpsPriceTieredBpsConfig] - billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -334,6 +685,27 @@ class PriceNewPlanTieredBpsPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PricePriceNewPlanGroupedWithMinMaxThresholdsPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -346,25 +718,64 @@ class PriceNewPlanTieredBpsPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" -class PriceNewPlanBpsPriceBpsConfig(TypedDict, total=False): - bps: Required[float] - """Basis point take rate per event""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - per_unit_maximum: Optional[str] - """Optional currency amount maximum to cap spend per event""" + 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 PriceNewPlanBpsPrice(TypedDict, total=False): - bps_config: Required[PriceNewPlanBpsPriceBpsConfig] - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class PricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig(TypedDict, total=False): + """Configuration for cumulative_grouped_allocation pricing""" + + cumulative_allocation: Required[str] + """The overall allocation across all groups""" + + group_allocation: Required[str] + """The allocation per individual group""" + + grouping_key: Required[str] + """The event property used to group usage before applying allocations""" + + unit_amount: Required[str] + """The amount to charge for each unit outside of the allocation""" + + +PricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PricePriceNewPlanCumulativeGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] """The cadence to bill for this price on.""" + cumulative_grouped_allocation_config: Required[ + PricePriceNewPlanCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + ] + """Configuration for cumulative_grouped_allocation pricing""" + item_id: Required[str] - """The id of the item the plan will be associated with.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["bps"]] + model_type: Required[Literal["cumulative_grouped_allocation"]] + """The pricing model type""" name: Required[str] """The name of the price.""" @@ -381,6 +792,27 @@ class PriceNewPlanBpsPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PricePriceNewPlanCumulativeGroupedAllocationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -393,36 +825,86 @@ class PriceNewPlanBpsPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceNewPlanBulkBpsPriceBulkBpsConfigTier(TypedDict, total=False): - bps: Required[float] - """Basis points to rate on""" + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ - maximum_amount: Optional[str] - """Upper bound for tier""" - per_unit_maximum: Optional[str] - """The maximum amount to charge for any one event""" +class PricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue(TypedDict, total=False): + """Per-dimension credit price for the daily credit allowance model.""" + dimension_values: Required[SequenceNotStr[Optional[str]]] + """One or two matrix keys to filter usage to this value by. -class PriceNewPlanBulkBpsPriceBulkBpsConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceNewPlanBulkBpsPriceBulkBpsConfigTier]] + For example, ["model"] could be used to apply a different credit rate to each AI + model. """ - Tiers for a bulk BPS pricing model where all usage is aggregated to a single - tier based on total volume + + unit_amount: Required[str] + """Credits charged per unit of usage matching the specified dimension_values""" + + +class PricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig(TypedDict, total=False): + """Configuration for daily_credit_allowance pricing""" + + daily_allowance: Required[str] + """Credits granted per day. Lose-it-or-use-it; does not roll over.""" + + default_unit_amount: Required[str] + """ + Default per-unit credit rate for any usage not bucketed into a specified + matrix_value + """ + + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" + + event_day_property: Required[str] + """Event property whose value identifies the day bucket the event belongs to (e.g. + + 'event_day' set to an ISO date string in the customer's timezone). The allowance + resets per distinct value of this property. """ + matrix_values: Required[Iterable[PricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue]] + """Per-dimension credit rates""" -class PriceNewPlanBulkBpsPrice(TypedDict, total=False): - bulk_bps_config: Required[PriceNewPlanBulkBpsPriceBulkBpsConfig] - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +PricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PricePriceNewPlanDailyCreditAllowancePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] """The cadence to bill for this price on.""" + daily_credit_allowance_config: Required[PricePriceNewPlanDailyCreditAllowancePriceDailyCreditAllowanceConfig] + """Configuration for daily_credit_allowance pricing""" + item_id: Required[str] - """The id of the item the plan will be associated with.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["bulk_bps"]] + model_type: Required[Literal["daily_credit_allowance"]] + """The pricing model type""" name: Required[str] """The name of the price.""" @@ -439,6 +921,27 @@ class PriceNewPlanBulkBpsPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PricePriceNewPlanDailyCreditAllowancePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -451,30 +954,79 @@ class PriceNewPlanBulkBpsPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig(TypedDict, total=False): + """Configuration for metered_allowance pricing""" + + allowance_grouping_value: Required[str] + """ + The grouping_key value whose summed quantity represents the allowance for this + period (e.g. 'storage_snapshot' emitting 3 × avg storage). Capped at consumption + — credit can never exceed actual usage. + """ + + consumption_grouping_value: Required[str] + """The grouping_key value whose summed quantity represents consumption (e.g. + + 'download'). Charged at unit_amount. + """ + + grouping_key: Required[str] + """ + Event property used to partition the metric into consumption and allowance + quantities (e.g. 'event_name'). The metric is queried with this key and the two + values below select which partition is which. + """ -class PriceNewPlanBulkPriceBulkConfigTier(TypedDict, total=False): unit_amount: Required[str] - """Amount per unit""" + """Per-unit price applied to gross consumption and to the allowance credit.""" - maximum_units: Optional[float] - """Upper bound for this tier""" + allowance_display_name: str + """Sub-line label for the credit row (e.g. 'Up to 3x free egress').""" + consumption_display_name: str + """Sub-line label for the gross consumption row (e.g. 'bytes gotten').""" -class PriceNewPlanBulkPriceBulkConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceNewPlanBulkPriceBulkConfigTier]] - """Bulk tiers for rating based on total usage volume""" +PricePriceNewPlanMeteredAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] -class PriceNewPlanBulkPrice(TypedDict, total=False): - bulk_config: Required[PriceNewPlanBulkPriceBulkConfig] - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class PricePriceNewPlanMeteredAllowancePrice(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.""" + """The id of the item the price will be associated with.""" + + metered_allowance_config: Required[PricePriceNewPlanMeteredAllowancePriceMeteredAllowanceConfig] + """Configuration for metered_allowance pricing""" - model_type: Required[Literal["bulk"]] + model_type: Required[Literal["metered_allowance"]] + """The pricing model type""" name: Required[str] """The name of the price.""" @@ -491,6 +1043,27 @@ class PriceNewPlanBulkPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PricePriceNewPlanMeteredAllowancePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -503,59 +1076,69 @@ class PriceNewPlanBulkPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceNewPlanThresholdTotalAmountPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] - """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.""" + If unspecified, a single invoice is produced per billing cycle. + """ - threshold_total_amount_config: Required[Dict[str, object]] + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - billable_metric_id: Optional[str] - """The id of the billable metric for the price. + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - Only needed if the price is usage-based. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. """ - billed_in_advance: Optional[bool] + reference_id: Optional[str] """ - 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. + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ - 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. +class PricePriceNewPlanPercentCompositePricePercentConfig(TypedDict, total=False): + """Configuration for percent pricing""" + + percent: Required[float] + """Fraction of the component subtotals to charge (0 < percent <= 1).""" + + maximum_amount: Optional[str] + """Maximum amount to charge. If unset, the fee has no upper bound.""" + + minimum_amount: Optional[str] + """Minimum amount to charge. If unset, the fee is bounded below by 0.""" + + prorated: bool + """If true, the minimum_amount is prorated based on the service period. + + The maximum_amount is an absolute cap (never prorated), and the percent applied + to upstream subtotals is never prorated either. """ - invoice_grouping_key: Optional[str] - """The property used to group this price on an invoice""" + +PricePriceNewPlanPercentCompositePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] -class PriceNewPlanTieredPackagePrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class PricePriceNewPlanPercentCompositePrice(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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["tiered_package"]] + model_type: Required[Literal["percent"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - tiered_package_config: Required[Dict[str, object]] + percent_config: Required[PricePriceNewPlanPercentCompositePricePercentConfig] + """Configuration for percent pricing""" billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -569,6 +1152,27 @@ class PriceNewPlanTieredPackagePrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PricePriceNewPlanPercentCompositePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -581,60 +1185,70 @@ class PriceNewPlanTieredPackagePrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceNewPlanTieredWithMinimumPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] - """The cadence to bill for this price on.""" + If unspecified, a single invoice is produced per billing cycle. + """ - item_id: Required[str] - """The id of the item the plan will be associated with.""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - model_type: Required[Literal["tiered_with_minimum"]] + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - name: Required[str] - """The name 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`. + """ - tiered_with_minimum_config: Required[Dict[str, object]] + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ - billable_metric_id: Optional[str] - """The id of the billable metric for the price. - Only needed if the price is usage-based. - """ +class PricePriceNewPlanEventOutputPriceEventOutputConfig(TypedDict, total=False): + """Configuration for event_output pricing""" - billed_in_advance: Optional[bool] + unit_rating_key: Required[str] + """The key in the event data to extract the unit rate from.""" + + default_unit_rate: Optional[str] """ - 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. + If provided, this amount will be used as the unit rate when an event does not + have a value for the `unit_rating_key`. If not provided, events missing a unit + rate will be ignored. """ - external_price_id: Optional[str] - """An alias for the price.""" + grouping_key: Optional[str] + """An optional key in the event data to group by (e.g., event ID). - fixed_price_quantity: Optional[float] - """ - If the Price represents a fixed cost, this represents the quantity of units - applied. + All events will also be grouped by their unit rate. """ - invoice_grouping_key: Optional[str] - """The property used to group this price on an invoice""" + +PricePriceNewPlanEventOutputPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] -class PriceNewPlanUnitWithPercentPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class PricePriceNewPlanEventOutputPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] """The cadence to bill for this price on.""" + event_output_config: Required[PricePriceNewPlanEventOutputPriceEventOutputConfig] + """Configuration for event_output pricing""" + item_id: Required[str] - """The id of the item the plan will be associated with.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["unit_with_percent"]] + model_type: Required[Literal["event_output"]] + """The pricing model type""" 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. @@ -647,6 +1261,27 @@ class PriceNewPlanUnitWithPercentPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PricePriceNewPlanEventOutputPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -659,58 +1294,162 @@ class PriceNewPlanUnitWithPercentPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceNewPlanPackageWithAllocationPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] - """The cadence to bill for this price on.""" + If unspecified, a single invoice is produced per billing cycle. + """ - item_id: Required[str] - """The id of the item the plan will be associated with.""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - model_type: Required[Literal["package_with_allocation"]] + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - name: Required[str] - """The name of the price.""" + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +PricePrice: TypeAlias = Union[ + NewPlanUnitPrice, + NewPlanTieredPrice, + NewPlanBulkPrice, + PricePriceNewPlanBulkWithFiltersPrice, + NewPlanPackagePrice, + NewPlanMatrixPrice, + NewPlanThresholdTotalAmountPrice, + NewPlanTieredPackagePrice, + NewPlanTieredWithMinimumPrice, + NewPlanGroupedTieredPrice, + NewPlanTieredPackageWithMinimumPrice, + NewPlanPackageWithAllocationPrice, + NewPlanUnitWithPercentPrice, + NewPlanMatrixWithAllocationPrice, + PricePriceNewPlanMatrixWithThresholdDiscountsPrice, + PricePriceNewPlanTieredWithProrationPrice, + NewPlanUnitWithProrationPrice, + NewPlanGroupedAllocationPrice, + NewPlanBulkWithProrationPrice, + NewPlanGroupedWithProratedMinimumPrice, + NewPlanGroupedWithMeteredMinimumPrice, + PricePriceNewPlanGroupedWithMinMaxThresholdsPrice, + NewPlanMatrixWithDisplayNamePrice, + NewPlanGroupedTieredPackagePrice, + NewPlanMaxGroupTieredPackagePrice, + NewPlanScalableMatrixWithUnitPricingPrice, + NewPlanScalableMatrixWithTieredPricingPrice, + NewPlanCumulativeGroupedBulkPrice, + PricePriceNewPlanCumulativeGroupedAllocationPrice, + PricePriceNewPlanDailyCreditAllowancePrice, + PricePriceNewPlanMeteredAllowancePrice, + NewPlanMinimumCompositePrice, + PricePriceNewPlanPercentCompositePrice, + PricePriceNewPlanEventOutputPrice, +] - package_with_allocation_config: Required[Dict[str, object]] - billable_metric_id: Optional[str] - """The id of the billable metric for the price. +class Price(TypedDict, total=False): + allocation_price: Optional[NewAllocationPrice] + """The allocation price to add to the plan.""" - Only needed if the price is usage-based. - """ + license_allocation_price: Optional[PriceLicenseAllocationPrice] + """The license allocation price to add to 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. - """ + plan_phase_order: Optional[int] + """The phase to add this price to.""" - external_price_id: Optional[str] - """An alias for the price.""" + price: Optional[PricePrice] + """New plan price request body params.""" - fixed_price_quantity: Optional[float] - """ - If the Price represents a fixed cost, this represents the quantity of units - applied. + +class AdjustmentAdjustmentNewTieredPercentageDiscountTier(TypedDict, total=False): + lower_bound: Required[float] + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: Required[float] + """The percentage (0-1) discounted from spend in this tier.""" + + upper_bound: Optional[float] + """Inclusive upper bound of cumulative spend; null for the final open-ended tier.""" + + +class AdjustmentAdjustmentNewTieredPercentageDiscountFilter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class AdjustmentAdjustmentNewTieredPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["tiered_percentage_discount"]] + + tiers: Required[Iterable[AdjustmentAdjustmentNewTieredPercentageDiscountTier]] + + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[Iterable[AdjustmentAdjustmentNewTieredPercentageDiscountFilter]] + """A list of filters that determine which prices this adjustment will apply to.""" + + 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. """ - invoice_grouping_key: Optional[str] - """The property used to group this price on an invoice""" + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" -Price = Union[ - PriceNewPlanUnitPrice, - PriceNewPlanPackagePrice, - PriceNewPlanMatrixPrice, - PriceNewPlanTieredPrice, - PriceNewPlanTieredBpsPrice, - PriceNewPlanBpsPrice, - PriceNewPlanBulkBpsPrice, - PriceNewPlanBulkPrice, - PriceNewPlanThresholdTotalAmountPrice, - PriceNewPlanTieredPackagePrice, - PriceNewPlanTieredWithMinimumPrice, - PriceNewPlanUnitWithPercentPrice, - PriceNewPlanPackageWithAllocationPrice, +AdjustmentAdjustment: TypeAlias = Union[ + NewPercentageDiscount, + NewUsageDiscount, + NewAmountDiscount, + NewMinimum, + NewMaximum, + AdjustmentAdjustmentNewTieredPercentageDiscount, ] + + +class Adjustment(TypedDict, total=False): + adjustment: Required[AdjustmentAdjustment] + """The definition of a new adjustment to create and add to the plan.""" + + plan_phase_order: Optional[int] + """The phase to add this adjustment to.""" + + +class PlanPhase(TypedDict, total=False): + order: Required[int] + """Determines the ordering of the phase in a plan's lifecycle. 1 = first phase.""" + + align_billing_with_phase_start_date: Optional[bool] + """Align billing cycle day with phase start date.""" + + duration: Optional[int] + """How many terms of length `duration_unit` this phase is active for. + + If null, this phase is evergreen and active indefinitely + """ + + duration_unit: Optional[Literal["daily", "monthly", "quarterly", "semi_annual", "annual"]] diff --git a/src/orb/types/plan_update_params.py b/src/orb/types/plan_update_params.py index 5fc717f0..c535603d 100644 --- a/src/orb/types/plan_update_params.py +++ b/src/orb/types/plan_update_params.py @@ -9,6 +9,9 @@ class PlanUpdateParams(TypedDict, total=False): + description: Optional[str] + """An optional user-defined description of the plan.""" + external_plan_id: Optional[str] """ An optional user-defined ID for this plan resource, used throughout the system diff --git a/src/orb/types/plan_version.py b/src/orb/types/plan_version.py new file mode 100644 index 00000000..32947800 --- /dev/null +++ b/src/orb/types/plan_version.py @@ -0,0 +1,133 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from .._utils import PropertyInfo +from .._models import BaseModel +from .shared.price import Price +from .plan_version_phase import PlanVersionPhase +from .shared.plan_phase_maximum_adjustment import PlanPhaseMaximumAdjustment +from .shared.plan_phase_minimum_adjustment import PlanPhaseMinimumAdjustment +from .shared.plan_phase_usage_discount_adjustment import PlanPhaseUsageDiscountAdjustment +from .shared.plan_phase_amount_discount_adjustment import PlanPhaseAmountDiscountAdjustment +from .shared.plan_phase_percentage_discount_adjustment import PlanPhasePercentageDiscountAdjustment + +__all__ = [ + "PlanVersion", + "Adjustment", + "AdjustmentPlanPhaseTieredPercentageDiscountAdjustment", + "AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentFilter", + "AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentTier", +] + + +class AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentTier(BaseModel): + """One band of a tiered percentage discount. + + Bounds are denominated in the discount's currency. + `lower_bound` is the exclusive start of the band and `upper_bound` is the inclusive end; + `upper_bound` is null only for the open-ended final tier. + """ + + lower_bound: float + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: float + """ + The percentage (between 0 and 1) discounted from spend that falls within this + tier. + """ + + upper_bound: Optional[float] = None + """ + Inclusive upper bound of cumulative spend for this tier; null for the final + open-ended tier. + """ + + +class AdjustmentPlanPhaseTieredPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["tiered_percentage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + filters: List[AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentFilter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, 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.""" + + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. + + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ + + tiers: List[AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentTier] + """ + The ordered, contiguous bands of cumulative eligible spend, each discounted at + its own percentage (progressive fill-a-tier), applied to the prices this + adjustment covers in a given billing period. + """ + + +Adjustment: TypeAlias = Annotated[ + Union[ + PlanPhaseUsageDiscountAdjustment, + PlanPhaseAmountDiscountAdjustment, + PlanPhasePercentageDiscountAdjustment, + AdjustmentPlanPhaseTieredPercentageDiscountAdjustment, + PlanPhaseMinimumAdjustment, + PlanPhaseMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + + +class PlanVersion(BaseModel): + """ + The PlanVersion resource represents the prices and adjustments present on a specific version of a plan. + """ + + adjustments: List[Adjustment] + """Adjustments for this plan. + + If the plan has phases, this includes adjustments across all phases of the plan. + """ + + created_at: datetime + + plan_phases: Optional[List[PlanVersionPhase]] = None + + prices: List[Price] + """Prices for this plan. + + If the plan has phases, this includes prices across all phases of the plan. + """ + + version: int diff --git a/src/orb/types/plan_version_phase.py b/src/orb/types/plan_version_phase.py new file mode 100644 index 00000000..4de75935 --- /dev/null +++ b/src/orb/types/plan_version_phase.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["PlanVersionPhase"] + + +class PlanVersionPhase(BaseModel): + id: str + + description: Optional[str] = None + + duration: Optional[int] = None + """How many terms of length `duration_unit` this phase is active for. + + If null, this phase is evergreen and active indefinitely + """ + + duration_unit: Optional[Literal["daily", "monthly", "quarterly", "semi_annual", "annual"]] = None + + name: str + + order: int + """Determines the ordering of the phase in a plan's lifecycle. 1 = first phase.""" diff --git a/src/orb/types/plans/__init__.py b/src/orb/types/plans/__init__.py index 6108b59a..37f6dbd3 100644 --- a/src/orb/types/plans/__init__.py +++ b/src/orb/types/plans/__init__.py @@ -2,4 +2,8 @@ from __future__ import annotations +from .migration_list_params import MigrationListParams as MigrationListParams +from .migration_list_response import MigrationListResponse as MigrationListResponse +from .migration_cancel_response import MigrationCancelResponse as MigrationCancelResponse +from .migration_retrieve_response import MigrationRetrieveResponse as MigrationRetrieveResponse from .external_plan_id_update_params import ExternalPlanIDUpdateParams as ExternalPlanIDUpdateParams diff --git a/src/orb/types/plans/external_plan_id_update_params.py b/src/orb/types/plans/external_plan_id_update_params.py index d7017899..7f58c79b 100644 --- a/src/orb/types/plans/external_plan_id_update_params.py +++ b/src/orb/types/plans/external_plan_id_update_params.py @@ -9,6 +9,9 @@ class ExternalPlanIDUpdateParams(TypedDict, total=False): + description: Optional[str] + """An optional user-defined description of the plan.""" + external_plan_id: Optional[str] """ An optional user-defined ID for this plan resource, used throughout the system diff --git a/src/orb/types/plans/migration_cancel_response.py b/src/orb/types/plans/migration_cancel_response.py new file mode 100644 index 00000000..8413360d --- /dev/null +++ b/src/orb/types/plans/migration_cancel_response.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from datetime import date, datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["MigrationCancelResponse"] + + +class MigrationCancelResponse(BaseModel): + id: str + """Unique identifier for this plan version change.""" + + effective_time: Union[date, datetime, Literal["end_of_term"], None] = None + """When the migration takes effect. + + Can be a specific date/time, or 'end_of_term' when scheduled to be at the end of + the current billing period. + """ + + plan_id: str + """The ID of the plan being migrated.""" + + status: Literal["not_started", "in_progress", "completed", "action_needed", "canceled"] + """ + Current status of the migration: 'not_started', 'in_progress', 'completed', + 'action_needed', or 'canceled'. + """ diff --git a/src/orb/types/plans/migration_list_params.py b/src/orb/types/plans/migration_list_params.py new file mode 100644 index 00000000..aecb3f1d --- /dev/null +++ b/src/orb/types/plans/migration_list_params.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +__all__ = ["MigrationListParams"] + + +class MigrationListParams(TypedDict, total=False): + 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.""" diff --git a/src/orb/types/plans/migration_list_response.py b/src/orb/types/plans/migration_list_response.py new file mode 100644 index 00000000..a6bfe53e --- /dev/null +++ b/src/orb/types/plans/migration_list_response.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from datetime import date, datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["MigrationListResponse"] + + +class MigrationListResponse(BaseModel): + id: str + """Unique identifier for this plan version change.""" + + effective_time: Union[date, datetime, Literal["end_of_term"], None] = None + """When the migration takes effect. + + Can be a specific date/time, or 'end_of_term' when scheduled to be at the end of + the current billing period. + """ + + plan_id: str + """The ID of the plan being migrated.""" + + status: Literal["not_started", "in_progress", "completed", "action_needed", "canceled"] + """ + Current status of the migration: 'not_started', 'in_progress', 'completed', + 'action_needed', or 'canceled'. + """ diff --git a/src/orb/types/plans/migration_retrieve_response.py b/src/orb/types/plans/migration_retrieve_response.py new file mode 100644 index 00000000..13488a26 --- /dev/null +++ b/src/orb/types/plans/migration_retrieve_response.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from datetime import date, datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["MigrationRetrieveResponse"] + + +class MigrationRetrieveResponse(BaseModel): + id: str + """Unique identifier for this plan version change.""" + + effective_time: Union[date, datetime, Literal["end_of_term"], None] = None + """When the migration takes effect. + + Can be a specific date/time, or 'end_of_term' when scheduled to be at the end of + the current billing period. + """ + + plan_id: str + """The ID of the plan being migrated.""" + + status: Literal["not_started", "in_progress", "completed", "action_needed", "canceled"] + """ + Current status of the migration: 'not_started', 'in_progress', 'completed', + 'action_needed', or 'canceled'. + """ diff --git a/src/orb/types/price.py b/src/orb/types/price.py deleted file mode 100644 index 9d9bd8e6..00000000 --- a/src/orb/types/price.py +++ /dev/null @@ -1,1241 +0,0 @@ -# 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 - -from pydantic import Field as FieldInfo - -from .shared import Discount -from .._models import BaseModel - -__all__ = [ - "Price", - "UnitPrice", - "UnitPriceBillableMetric", - "UnitPriceItem", - "UnitPriceMaximum", - "UnitPriceMinimum", - "UnitPriceUnitConfig", - "PackagePrice", - "PackagePriceBillableMetric", - "PackagePriceItem", - "PackagePriceMaximum", - "PackagePriceMinimum", - "PackagePricePackageConfig", - "MatrixPrice", - "MatrixPriceBillableMetric", - "MatrixPriceItem", - "MatrixPriceMatrixConfig", - "MatrixPriceMatrixConfigMatrixValue", - "MatrixPriceMaximum", - "MatrixPriceMinimum", - "TieredPrice", - "TieredPriceBillableMetric", - "TieredPriceItem", - "TieredPriceMaximum", - "TieredPriceMinimum", - "TieredPriceTieredConfig", - "TieredPriceTieredConfigTier", - "TieredBpsPrice", - "TieredBpsPriceBillableMetric", - "TieredBpsPriceItem", - "TieredBpsPriceMaximum", - "TieredBpsPriceMinimum", - "TieredBpsPriceTieredBpsConfig", - "TieredBpsPriceTieredBpsConfigTier", - "BpsPrice", - "BpsPriceBillableMetric", - "BpsPriceBpsConfig", - "BpsPriceItem", - "BpsPriceMaximum", - "BpsPriceMinimum", - "BulkBpsPrice", - "BulkBpsPriceBillableMetric", - "BulkBpsPriceBulkBpsConfig", - "BulkBpsPriceBulkBpsConfigTier", - "BulkBpsPriceItem", - "BulkBpsPriceMaximum", - "BulkBpsPriceMinimum", - "BulkPrice", - "BulkPriceBillableMetric", - "BulkPriceBulkConfig", - "BulkPriceBulkConfigTier", - "BulkPriceItem", - "BulkPriceMaximum", - "BulkPriceMinimum", - "ThresholdTotalAmountPrice", - "ThresholdTotalAmountPriceBillableMetric", - "ThresholdTotalAmountPriceItem", - "ThresholdTotalAmountPriceMaximum", - "ThresholdTotalAmountPriceMinimum", - "TieredPackagePrice", - "TieredPackagePriceBillableMetric", - "TieredPackagePriceItem", - "TieredPackagePriceMaximum", - "TieredPackagePriceMinimum", - "TieredWithMinimumPrice", - "TieredWithMinimumPriceBillableMetric", - "TieredWithMinimumPriceItem", - "TieredWithMinimumPriceMaximum", - "TieredWithMinimumPriceMinimum", - "PackageWithAllocationPrice", - "PackageWithAllocationPriceBillableMetric", - "PackageWithAllocationPriceItem", - "PackageWithAllocationPriceMaximum", - "PackageWithAllocationPriceMinimum", - "UnitWithPercentPrice", - "UnitWithPercentPriceBillableMetric", - "UnitWithPercentPriceItem", - "UnitWithPercentPriceMaximum", - "UnitWithPercentPriceMinimum", - "MatrixWithAllocationPrice", - "MatrixWithAllocationPriceBillableMetric", - "MatrixWithAllocationPriceItem", - "MatrixWithAllocationPriceMatrixWithAllocationConfig", - "MatrixWithAllocationPriceMatrixWithAllocationConfigMatrixValue", - "MatrixWithAllocationPriceMaximum", - "MatrixWithAllocationPriceMinimum", -] - - -class UnitPriceBillableMetric(BaseModel): - id: str - - -class UnitPriceItem(BaseModel): - id: str - - name: str - - -class UnitPriceMaximum(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 UnitPriceMinimum(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 UnitPriceUnitConfig(BaseModel): - unit_amount: str - """Rate per unit of usage""" - - -class UnitPrice(BaseModel): - id: str - - billable_metric: Optional[UnitPriceBillableMetric] = None - - cadence: Literal["one_time", "monthly", "quarterly", "annual"] - - created_at: datetime - - currency: str - - discount: Optional[Discount] = None - - external_price_id: Optional[str] = None - - fixed_price_quantity: Optional[float] = None - - item: UnitPriceItem - - maximum: Optional[UnitPriceMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[UnitPriceMinimum] = None - - minimum_amount: Optional[str] = None - - price_model_type: Literal["unit"] = FieldInfo(alias="model_type") - - name: str - - plan_phase_order: Optional[int] = None - - price_type: Literal["usage_price", "fixed_price"] - - unit_config: UnitPriceUnitConfig - - -class PackagePriceBillableMetric(BaseModel): - id: str - - -class PackagePriceItem(BaseModel): - id: str - - name: str - - -class PackagePriceMaximum(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 PackagePriceMinimum(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 PackagePricePackageConfig(BaseModel): - package_amount: str - """A currency amount to rate usage by""" - - package_size: Optional[int] = None - """An integer amount to represent package size. - - For example, 1000 here would divide usage by 1000 before multiplying by - package_amount in rating - """ - - -class PackagePrice(BaseModel): - id: str - - billable_metric: Optional[PackagePriceBillableMetric] = None - - cadence: Literal["one_time", "monthly", "quarterly", "annual"] - - created_at: datetime - - currency: str - - discount: Optional[Discount] = None - - external_price_id: Optional[str] = None - - fixed_price_quantity: Optional[float] = None - - item: PackagePriceItem - - maximum: Optional[PackagePriceMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[PackagePriceMinimum] = None - - minimum_amount: Optional[str] = None - - price_model_type: Literal["package"] = FieldInfo(alias="model_type") - - name: str - - package_config: PackagePricePackageConfig - - plan_phase_order: Optional[int] = None - - price_type: Literal["usage_price", "fixed_price"] - - -class MatrixPriceBillableMetric(BaseModel): - id: str - - -class MatrixPriceItem(BaseModel): - id: str - - name: str - - -class MatrixPriceMatrixConfigMatrixValue(BaseModel): - dimension_values: 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: str - """Unit price for the specified dimension_values""" - - -class MatrixPriceMatrixConfig(BaseModel): - default_unit_amount: str - """Default per unit rate for any usage not bucketed into a specified matrix_value""" - - dimensions: List[Optional[str]] - """One or two event property values to evaluate matrix groups by""" - - matrix_values: List[MatrixPriceMatrixConfigMatrixValue] - """Matrix values for specified matrix grouping keys""" - - -class MatrixPriceMaximum(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 MatrixPriceMinimum(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 MatrixPrice(BaseModel): - id: str - - billable_metric: Optional[MatrixPriceBillableMetric] = None - - cadence: Literal["one_time", "monthly", "quarterly", "annual"] - - created_at: datetime - - currency: str - - discount: Optional[Discount] = None - - external_price_id: Optional[str] = None - - fixed_price_quantity: Optional[float] = None - - item: MatrixPriceItem - - matrix_config: MatrixPriceMatrixConfig - - maximum: Optional[MatrixPriceMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[MatrixPriceMinimum] = None - - minimum_amount: Optional[str] = None - - price_model_type: Literal["matrix"] = FieldInfo(alias="model_type") - - name: str - - plan_phase_order: Optional[int] = None - - price_type: Literal["usage_price", "fixed_price"] - - -class TieredPriceBillableMetric(BaseModel): - id: str - - -class TieredPriceItem(BaseModel): - id: str - - name: str - - -class TieredPriceMaximum(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 TieredPriceMinimum(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 TieredPriceTieredConfigTier(BaseModel): - first_unit: float - """Inclusive tier starting value""" - - unit_amount: str - """Amount per unit""" - - last_unit: Optional[float] = None - """Exclusive tier ending value. If null, this is treated as the last tier""" - - -class TieredPriceTieredConfig(BaseModel): - tiers: List[TieredPriceTieredConfigTier] - """Tiers for rating based on total usage quantities into the specified tier""" - - -class TieredPrice(BaseModel): - id: str - - billable_metric: Optional[TieredPriceBillableMetric] = None - - cadence: Literal["one_time", "monthly", "quarterly", "annual"] - - created_at: datetime - - currency: str - - discount: Optional[Discount] = None - - external_price_id: Optional[str] = None - - fixed_price_quantity: Optional[float] = None - - item: TieredPriceItem - - maximum: Optional[TieredPriceMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[TieredPriceMinimum] = None - - minimum_amount: Optional[str] = None - - price_model_type: Literal["tiered"] = FieldInfo(alias="model_type") - - name: str - - plan_phase_order: Optional[int] = None - - price_type: Literal["usage_price", "fixed_price"] - - tiered_config: TieredPriceTieredConfig - - -class TieredBpsPriceBillableMetric(BaseModel): - id: str - - -class TieredBpsPriceItem(BaseModel): - id: str - - name: str - - -class TieredBpsPriceMaximum(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 TieredBpsPriceMinimum(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 TieredBpsPriceTieredBpsConfigTier(BaseModel): - bps: float - """Per-event basis point rate""" - - minimum_amount: str - """Inclusive tier starting value""" - - maximum_amount: Optional[str] = None - """Exclusive tier ending value""" - - per_unit_maximum: Optional[str] = None - """Per unit maximum to charge""" - - -class TieredBpsPriceTieredBpsConfig(BaseModel): - tiers: List[TieredBpsPriceTieredBpsConfigTier] - """ - Tiers for a Graduated BPS pricing model, where usage is bucketed into specified - tiers - """ - - -class TieredBpsPrice(BaseModel): - id: str - - billable_metric: Optional[TieredBpsPriceBillableMetric] = None - - cadence: Literal["one_time", "monthly", "quarterly", "annual"] - - created_at: datetime - - currency: str - - discount: Optional[Discount] = None - - external_price_id: Optional[str] = None - - fixed_price_quantity: Optional[float] = None - - item: TieredBpsPriceItem - - maximum: Optional[TieredBpsPriceMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[TieredBpsPriceMinimum] = None - - minimum_amount: Optional[str] = None - - price_model_type: Literal["tiered_bps"] = FieldInfo(alias="model_type") - - name: str - - plan_phase_order: Optional[int] = None - - price_type: Literal["usage_price", "fixed_price"] - - tiered_bps_config: TieredBpsPriceTieredBpsConfig - - -class BpsPriceBillableMetric(BaseModel): - id: str - - -class BpsPriceBpsConfig(BaseModel): - bps: float - """Basis point take rate per event""" - - per_unit_maximum: Optional[str] = None - """Optional currency amount maximum to cap spend per event""" - - -class BpsPriceItem(BaseModel): - id: str - - name: str - - -class BpsPriceMaximum(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 BpsPriceMinimum(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 BpsPrice(BaseModel): - id: str - - billable_metric: Optional[BpsPriceBillableMetric] = None - - bps_config: BpsPriceBpsConfig - - cadence: Literal["one_time", "monthly", "quarterly", "annual"] - - created_at: datetime - - currency: str - - discount: Optional[Discount] = None - - external_price_id: Optional[str] = None - - fixed_price_quantity: Optional[float] = None - - item: BpsPriceItem - - maximum: Optional[BpsPriceMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[BpsPriceMinimum] = None - - minimum_amount: Optional[str] = None - - price_model_type: Literal["bps"] = FieldInfo(alias="model_type") - - name: str - - plan_phase_order: Optional[int] = None - - price_type: Literal["usage_price", "fixed_price"] - - -class BulkBpsPriceBillableMetric(BaseModel): - id: str - - -class BulkBpsPriceBulkBpsConfigTier(BaseModel): - bps: float - """Basis points to rate on""" - - maximum_amount: Optional[str] = None - """Upper bound for tier""" - - per_unit_maximum: Optional[str] = None - """The maximum amount to charge for any one event""" - - -class BulkBpsPriceBulkBpsConfig(BaseModel): - tiers: List[BulkBpsPriceBulkBpsConfigTier] - """ - Tiers for a bulk BPS pricing model where all usage is aggregated to a single - tier based on total volume - """ - - -class BulkBpsPriceItem(BaseModel): - id: str - - name: str - - -class BulkBpsPriceMaximum(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 BulkBpsPriceMinimum(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 BulkBpsPrice(BaseModel): - id: str - - billable_metric: Optional[BulkBpsPriceBillableMetric] = None - - bulk_bps_config: BulkBpsPriceBulkBpsConfig - - cadence: Literal["one_time", "monthly", "quarterly", "annual"] - - created_at: datetime - - currency: str - - discount: Optional[Discount] = None - - external_price_id: Optional[str] = None - - fixed_price_quantity: Optional[float] = None - - item: BulkBpsPriceItem - - maximum: Optional[BulkBpsPriceMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[BulkBpsPriceMinimum] = None - - minimum_amount: Optional[str] = None - - price_model_type: Literal["bulk_bps"] = FieldInfo(alias="model_type") - - name: str - - plan_phase_order: Optional[int] = None - - price_type: Literal["usage_price", "fixed_price"] - - -class BulkPriceBillableMetric(BaseModel): - id: str - - -class BulkPriceBulkConfigTier(BaseModel): - unit_amount: str - """Amount per unit""" - - maximum_units: Optional[float] = None - """Upper bound for this tier""" - - -class BulkPriceBulkConfig(BaseModel): - tiers: List[BulkPriceBulkConfigTier] - """Bulk tiers for rating based on total usage volume""" - - -class BulkPriceItem(BaseModel): - id: str - - name: str - - -class BulkPriceMaximum(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 BulkPriceMinimum(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 BulkPrice(BaseModel): - id: str - - billable_metric: Optional[BulkPriceBillableMetric] = None - - bulk_config: BulkPriceBulkConfig - - cadence: Literal["one_time", "monthly", "quarterly", "annual"] - - created_at: datetime - - currency: str - - discount: Optional[Discount] = None - - external_price_id: Optional[str] = None - - fixed_price_quantity: Optional[float] = None - - item: BulkPriceItem - - maximum: Optional[BulkPriceMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[BulkPriceMinimum] = None - - minimum_amount: Optional[str] = None - - price_model_type: Literal["bulk"] = FieldInfo(alias="model_type") - - name: str - - plan_phase_order: Optional[int] = None - - price_type: Literal["usage_price", "fixed_price"] - - -class ThresholdTotalAmountPriceBillableMetric(BaseModel): - id: str - - -class ThresholdTotalAmountPriceItem(BaseModel): - id: str - - name: str - - -class ThresholdTotalAmountPriceMaximum(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 ThresholdTotalAmountPriceMinimum(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 ThresholdTotalAmountPrice(BaseModel): - id: str - - billable_metric: Optional[ThresholdTotalAmountPriceBillableMetric] = None - - cadence: Literal["one_time", "monthly", "quarterly", "annual"] - - created_at: datetime - - currency: str - - discount: Optional[Discount] = None - - external_price_id: Optional[str] = None - - fixed_price_quantity: Optional[float] = None - - item: ThresholdTotalAmountPriceItem - - maximum: Optional[ThresholdTotalAmountPriceMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[ThresholdTotalAmountPriceMinimum] = None - - minimum_amount: Optional[str] = None - - price_model_type: Literal["threshold_total_amount"] = FieldInfo(alias="model_type") - - name: str - - plan_phase_order: Optional[int] = None - - price_type: Literal["usage_price", "fixed_price"] - - threshold_total_amount_config: Dict[str, object] - - -class TieredPackagePriceBillableMetric(BaseModel): - id: str - - -class TieredPackagePriceItem(BaseModel): - id: str - - name: str - - -class TieredPackagePriceMaximum(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 TieredPackagePriceMinimum(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 TieredPackagePrice(BaseModel): - id: str - - billable_metric: Optional[TieredPackagePriceBillableMetric] = None - - cadence: Literal["one_time", "monthly", "quarterly", "annual"] - - created_at: datetime - - currency: str - - discount: Optional[Discount] = None - - external_price_id: Optional[str] = None - - fixed_price_quantity: Optional[float] = None - - item: TieredPackagePriceItem - - maximum: Optional[TieredPackagePriceMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[TieredPackagePriceMinimum] = None - - minimum_amount: Optional[str] = None - - price_model_type: Literal["tiered_package"] = FieldInfo(alias="model_type") - - name: str - - plan_phase_order: Optional[int] = None - - price_type: Literal["usage_price", "fixed_price"] - - tiered_package_config: Dict[str, object] - - -class TieredWithMinimumPriceBillableMetric(BaseModel): - id: str - - -class TieredWithMinimumPriceItem(BaseModel): - id: str - - name: str - - -class TieredWithMinimumPriceMaximum(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 TieredWithMinimumPriceMinimum(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 TieredWithMinimumPrice(BaseModel): - id: str - - billable_metric: Optional[TieredWithMinimumPriceBillableMetric] = None - - cadence: Literal["one_time", "monthly", "quarterly", "annual"] - - created_at: datetime - - currency: str - - discount: Optional[Discount] = None - - external_price_id: Optional[str] = None - - fixed_price_quantity: Optional[float] = None - - item: TieredWithMinimumPriceItem - - maximum: Optional[TieredWithMinimumPriceMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[TieredWithMinimumPriceMinimum] = None - - minimum_amount: Optional[str] = None - - price_model_type: Literal["tiered_with_minimum"] = FieldInfo(alias="model_type") - - name: str - - plan_phase_order: Optional[int] = None - - price_type: Literal["usage_price", "fixed_price"] - - tiered_with_minimum_config: Dict[str, object] - - -class PackageWithAllocationPriceBillableMetric(BaseModel): - id: str - - -class PackageWithAllocationPriceItem(BaseModel): - id: str - - name: str - - -class PackageWithAllocationPriceMaximum(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 PackageWithAllocationPriceMinimum(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 PackageWithAllocationPrice(BaseModel): - id: str - - billable_metric: Optional[PackageWithAllocationPriceBillableMetric] = None - - cadence: Literal["one_time", "monthly", "quarterly", "annual"] - - created_at: datetime - - currency: str - - discount: Optional[Discount] = None - - external_price_id: Optional[str] = None - - fixed_price_quantity: Optional[float] = None - - item: PackageWithAllocationPriceItem - - maximum: Optional[PackageWithAllocationPriceMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[PackageWithAllocationPriceMinimum] = None - - minimum_amount: Optional[str] = None - - price_model_type: Literal["package_with_allocation"] = FieldInfo(alias="model_type") - - name: str - - package_with_allocation_config: Dict[str, object] - - plan_phase_order: Optional[int] = None - - price_type: Literal["usage_price", "fixed_price"] - - -class UnitWithPercentPriceBillableMetric(BaseModel): - id: str - - -class UnitWithPercentPriceItem(BaseModel): - id: str - - name: str - - -class UnitWithPercentPriceMaximum(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 UnitWithPercentPriceMinimum(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 UnitWithPercentPrice(BaseModel): - id: str - - billable_metric: Optional[UnitWithPercentPriceBillableMetric] = None - - cadence: Literal["one_time", "monthly", "quarterly", "annual"] - - created_at: datetime - - currency: str - - discount: Optional[Discount] = None - - external_price_id: Optional[str] = None - - fixed_price_quantity: Optional[float] = None - - item: UnitWithPercentPriceItem - - maximum: Optional[UnitWithPercentPriceMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[UnitWithPercentPriceMinimum] = None - - minimum_amount: Optional[str] = None - - price_model_type: Literal["unit_with_percent"] = FieldInfo(alias="model_type") - - name: str - - plan_phase_order: Optional[int] = None - - price_type: Literal["usage_price", "fixed_price"] - - unit_with_percent_config: Dict[str, object] - - -class MatrixWithAllocationPriceBillableMetric(BaseModel): - id: str - - -class MatrixWithAllocationPriceItem(BaseModel): - id: str - - name: str - - -class MatrixWithAllocationPriceMatrixWithAllocationConfigMatrixValue(BaseModel): - dimension_values: 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: str - """Unit price for the specified dimension_values""" - - -class MatrixWithAllocationPriceMatrixWithAllocationConfig(BaseModel): - allocation: float - """Allocation to be used to calculate the price""" - - default_unit_amount: str - """Default per unit rate for any usage not bucketed into a specified matrix_value""" - - dimensions: List[Optional[str]] - """One or two event property values to evaluate matrix groups by""" - - matrix_values: List[MatrixWithAllocationPriceMatrixWithAllocationConfigMatrixValue] - """Matrix values for specified matrix grouping keys""" - - -class MatrixWithAllocationPriceMaximum(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 MatrixWithAllocationPriceMinimum(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 MatrixWithAllocationPrice(BaseModel): - id: str - - billable_metric: Optional[MatrixWithAllocationPriceBillableMetric] = None - - cadence: Literal["one_time", "monthly", "quarterly", "annual"] - - created_at: datetime - - currency: str - - discount: Optional[Discount] = None - - external_price_id: Optional[str] = None - - fixed_price_quantity: Optional[float] = None - - item: MatrixWithAllocationPriceItem - - matrix_with_allocation_config: MatrixWithAllocationPriceMatrixWithAllocationConfig - - maximum: Optional[MatrixWithAllocationPriceMaximum] = None - - maximum_amount: Optional[str] = None - - minimum: Optional[MatrixWithAllocationPriceMinimum] = None - - minimum_amount: Optional[str] = None - - price_model_type: Literal["matrix_with_allocation"] = FieldInfo(alias="model_type") - - name: str - - plan_phase_order: Optional[int] = None - - price_type: Literal["usage_price", "fixed_price"] - - -Price = Union[ - UnitPrice, - PackagePrice, - MatrixPrice, - TieredPrice, - TieredBpsPrice, - BpsPrice, - BulkBpsPrice, - BulkPrice, - ThresholdTotalAmountPrice, - TieredPackagePrice, - TieredWithMinimumPrice, - PackageWithAllocationPrice, - UnitWithPercentPrice, - MatrixWithAllocationPrice, -] diff --git a/src/orb/types/price_create_params.py b/src/orb/types/price_create_params.py index 92a17806..c5148f57 100644 --- a/src/orb/types/price_create_params.py +++ b/src/orb/types/price_create_params.py @@ -2,60 +2,161 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .shared_params.bulk_config import BulkConfig +from .shared_params.unit_config import UnitConfig +from .shared_params.matrix_config import MatrixConfig +from .shared_params.tiered_config import TieredConfig +from .shared_params.package_config import PackageConfig +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.matrix_with_allocation_config import MatrixWithAllocationConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration __all__ = [ "PriceCreateParams", "NewFloatingUnitPrice", - "NewFloatingUnitPriceUnitConfig", - "NewFloatingPackagePrice", - "NewFloatingPackagePricePackageConfig", - "NewFloatingMatrixPrice", - "NewFloatingMatrixPriceMatrixConfig", - "NewFloatingMatrixPriceMatrixConfigMatrixValue", - "NewFloatingMatrixWithAllocationPrice", - "NewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfig", - "NewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfigMatrixValue", + "NewFloatingUnitPriceConversionRateConfig", "NewFloatingTieredPrice", - "NewFloatingTieredPriceTieredConfig", - "NewFloatingTieredPriceTieredConfigTier", - "NewFloatingTieredBpsPrice", - "NewFloatingTieredBpsPriceTieredBpsConfig", - "NewFloatingTieredBpsPriceTieredBpsConfigTier", - "NewFloatingBpsPrice", - "NewFloatingBpsPriceBpsConfig", - "NewFloatingBulkBpsPrice", - "NewFloatingBulkBpsPriceBulkBpsConfig", - "NewFloatingBulkBpsPriceBulkBpsConfigTier", + "NewFloatingTieredPriceConversionRateConfig", "NewFloatingBulkPrice", - "NewFloatingBulkPriceBulkConfig", - "NewFloatingBulkPriceBulkConfigTier", + "NewFloatingBulkPriceConversionRateConfig", + "NewFloatingBulkWithFiltersPrice", + "NewFloatingBulkWithFiltersPriceBulkWithFiltersConfig", + "NewFloatingBulkWithFiltersPriceBulkWithFiltersConfigFilter", + "NewFloatingBulkWithFiltersPriceBulkWithFiltersConfigTier", + "NewFloatingBulkWithFiltersPriceConversionRateConfig", + "NewFloatingPackagePrice", + "NewFloatingPackagePriceConversionRateConfig", + "NewFloatingMatrixPrice", + "NewFloatingMatrixPriceConversionRateConfig", "NewFloatingThresholdTotalAmountPrice", + "NewFloatingThresholdTotalAmountPriceThresholdTotalAmountConfig", + "NewFloatingThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable", + "NewFloatingThresholdTotalAmountPriceConversionRateConfig", "NewFloatingTieredPackagePrice", + "NewFloatingTieredPackagePriceTieredPackageConfig", + "NewFloatingTieredPackagePriceTieredPackageConfigTier", + "NewFloatingTieredPackagePriceConversionRateConfig", "NewFloatingTieredWithMinimumPrice", - "NewFloatingPackageWithAllocationPrice", + "NewFloatingTieredWithMinimumPriceTieredWithMinimumConfig", + "NewFloatingTieredWithMinimumPriceTieredWithMinimumConfigTier", + "NewFloatingTieredWithMinimumPriceConversionRateConfig", + "NewFloatingGroupedTieredPrice", + "NewFloatingGroupedTieredPriceGroupedTieredConfig", + "NewFloatingGroupedTieredPriceGroupedTieredConfigTier", + "NewFloatingGroupedTieredPriceConversionRateConfig", "NewFloatingTieredPackageWithMinimumPrice", + "NewFloatingTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig", + "NewFloatingTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier", + "NewFloatingTieredPackageWithMinimumPriceConversionRateConfig", + "NewFloatingPackageWithAllocationPrice", + "NewFloatingPackageWithAllocationPricePackageWithAllocationConfig", + "NewFloatingPackageWithAllocationPriceConversionRateConfig", "NewFloatingUnitWithPercentPrice", + "NewFloatingUnitWithPercentPriceUnitWithPercentConfig", + "NewFloatingUnitWithPercentPriceConversionRateConfig", + "NewFloatingMatrixWithAllocationPrice", + "NewFloatingMatrixWithAllocationPriceConversionRateConfig", + "NewFloatingMatrixWithThresholdDiscountsPrice", + "NewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig", + "NewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue", + "NewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup", + "NewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig", + "NewFloatingTieredWithProrationPrice", + "NewFloatingTieredWithProrationPriceTieredWithProrationConfig", + "NewFloatingTieredWithProrationPriceTieredWithProrationConfigTier", + "NewFloatingTieredWithProrationPriceConversionRateConfig", + "NewFloatingUnitWithProrationPrice", + "NewFloatingUnitWithProrationPriceUnitWithProrationConfig", + "NewFloatingUnitWithProrationPriceConversionRateConfig", + "NewFloatingGroupedAllocationPrice", + "NewFloatingGroupedAllocationPriceGroupedAllocationConfig", + "NewFloatingGroupedAllocationPriceConversionRateConfig", + "NewFloatingBulkWithProrationPrice", + "NewFloatingBulkWithProrationPriceBulkWithProrationConfig", + "NewFloatingBulkWithProrationPriceBulkWithProrationConfigTier", + "NewFloatingBulkWithProrationPriceConversionRateConfig", + "NewFloatingGroupedWithProratedMinimumPrice", + "NewFloatingGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig", + "NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig", + "NewFloatingGroupedWithMeteredMinimumPrice", + "NewFloatingGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig", + "NewFloatingGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor", + "NewFloatingGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount", + "NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig", + "NewFloatingGroupedWithMinMaxThresholdsPrice", + "NewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig", + "NewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig", + "NewFloatingMatrixWithDisplayNamePrice", + "NewFloatingMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig", + "NewFloatingMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount", + "NewFloatingMatrixWithDisplayNamePriceConversionRateConfig", + "NewFloatingGroupedTieredPackagePrice", + "NewFloatingGroupedTieredPackagePriceGroupedTieredPackageConfig", + "NewFloatingGroupedTieredPackagePriceGroupedTieredPackageConfigTier", + "NewFloatingGroupedTieredPackagePriceConversionRateConfig", + "NewFloatingMaxGroupTieredPackagePrice", + "NewFloatingMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig", + "NewFloatingMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier", + "NewFloatingMaxGroupTieredPackagePriceConversionRateConfig", + "NewFloatingScalableMatrixWithUnitPricingPrice", + "NewFloatingScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig", + "NewFloatingScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor", + "NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig", + "NewFloatingScalableMatrixWithTieredPricingPrice", + "NewFloatingScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig", + "NewFloatingScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor", + "NewFloatingScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier", + "NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig", + "NewFloatingCumulativeGroupedBulkPrice", + "NewFloatingCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig", + "NewFloatingCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue", + "NewFloatingCumulativeGroupedBulkPriceConversionRateConfig", + "NewFloatingCumulativeGroupedAllocationPrice", + "NewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig", + "NewFloatingCumulativeGroupedAllocationPriceConversionRateConfig", + "NewFloatingDailyCreditAllowancePrice", + "NewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig", + "NewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue", + "NewFloatingDailyCreditAllowancePriceConversionRateConfig", + "NewFloatingMeteredAllowancePrice", + "NewFloatingMeteredAllowancePriceMeteredAllowanceConfig", + "NewFloatingMeteredAllowancePriceConversionRateConfig", + "NewFloatingMinimumCompositePrice", + "NewFloatingMinimumCompositePriceMinimumCompositeConfig", + "NewFloatingMinimumCompositePriceConversionRateConfig", + "NewFloatingPercentCompositePrice", + "NewFloatingPercentCompositePricePercentConfig", + "NewFloatingPercentCompositePriceConversionRateConfig", + "NewFloatingEventOutputPrice", + "NewFloatingEventOutputPriceEventOutputConfig", + "NewFloatingEventOutputPriceConversionRateConfig", ] class NewFloatingUnitPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] + 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.""" + """The id of the item the price will be associated with.""" model_type: Required[Literal["unit"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - unit_config: Required[NewFloatingUnitPriceUnitConfig] + unit_config: Required[UnitConfig] + """Configuration for unit pricing""" billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -69,6 +170,21 @@ class NewFloatingUnitPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingUnitPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -81,28 +197,44 @@ class NewFloatingUnitPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class NewFloatingUnitPriceUnitConfig(TypedDict, total=False): - unit_amount: Required[str] - """Rate per unit of usage""" + If unspecified, a single invoice is produced per billing cycle. + """ + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" -class NewFloatingPackagePrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] + 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`. + """ + + +NewFloatingUnitPriceConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingTieredPrice(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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["package"]] + model_type: Required[Literal["tiered"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - package_config: Required[NewFloatingPackagePricePackageConfig] + tiered_config: Required[TieredConfig] + """Configuration for tiered pricing""" billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -116,6 +248,21 @@ class NewFloatingPackagePrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingTieredPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -128,32 +275,41 @@ class NewFloatingPackagePrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class NewFloatingPackagePricePackageConfig(TypedDict, total=False): - package_amount: Required[str] - """A currency amount to rate usage by""" + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - package_size: Optional[int] - """An integer amount to represent package size. + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - For example, 1000 here would divide usage by 1000 before multiplying by - package_amount in rating + 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 NewFloatingMatrixPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +NewFloatingTieredPriceConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingBulkPrice(TypedDict, total=False): + bulk_config: Required[BulkConfig] + """Configuration for bulk pricing""" + + 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_config: Required[NewFloatingMatrixPriceMatrixConfig] + """The id of the item the price will be associated with.""" - model_type: Required[Literal["matrix"]] + model_type: Required[Literal["bulk"]] + """The pricing model type""" name: Required[str] """The name of the price.""" @@ -170,6 +326,21 @@ class NewFloatingMatrixPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingBulkPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -182,43 +353,41 @@ class NewFloatingMatrixPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class NewFloatingMatrixPriceMatrixConfigMatrixValue(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. + If unspecified, a single invoice is produced per billing cycle. """ - unit_amount: Required[str] - """Unit price for the specified dimension_values""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. -class NewFloatingMatrixPriceMatrixConfig(TypedDict, total=False): - default_unit_amount: Required[str] - """Default per unit rate for any usage not bucketed into a specified matrix_value""" + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - dimensions: Required[List[Optional[str]]] - """One or two event property values to evaluate matrix groups by""" - matrix_values: Required[Iterable[NewFloatingMatrixPriceMatrixConfigMatrixValue]] - """Matrix values for specified matrix grouping keys""" +NewFloatingBulkPriceConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] -class NewFloatingMatrixWithAllocationPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class NewFloatingBulkWithFiltersPrice(TypedDict, total=False): + bulk_with_filters_config: Required[NewFloatingBulkWithFiltersPriceBulkWithFiltersConfig] + """Configuration for bulk_with_filters pricing""" + + 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_allocation_config: Required[NewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfig] + """The id of the item the price will be associated with.""" - model_type: Required[Literal["matrix_with_allocation"]] + model_type: Required[Literal["bulk_with_filters"]] + """The pricing model type""" name: Required[str] """The name of the price.""" @@ -235,6 +404,21 @@ class NewFloatingMatrixWithAllocationPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingBulkWithFiltersPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -247,49 +431,76 @@ class NewFloatingMatrixWithAllocationPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" -class NewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfigMatrixValue(TypedDict, total=False): - dimension_values: Required[List[Optional[str]]] - """One or two matrix keys to filter usage to this Matrix value by. + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - For example, ["region", "tier"] could be used to filter cloud usage by a cloud - region and an instance tier. + 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 NewFloatingBulkWithFiltersPriceBulkWithFiltersConfigFilter(TypedDict, total=False): + """Configuration for a single property filter""" + + property_key: Required[str] + """Event property key to filter on""" + + property_value: Required[str] + """Event property value to match""" + + +class NewFloatingBulkWithFiltersPriceBulkWithFiltersConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier""" + unit_amount: Required[str] - """Unit price for the specified dimension_values""" + """Amount per unit""" + tier_lower_bound: Optional[str] + """The lower bound for this tier""" -class NewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfig(TypedDict, total=False): - allocation: Required[float] - """Allocation to be used to calculate the price""" - default_unit_amount: Required[str] - """Default per unit rate for any usage not bucketed into a specified matrix_value""" +class NewFloatingBulkWithFiltersPriceBulkWithFiltersConfig(TypedDict, total=False): + """Configuration for bulk_with_filters pricing""" - dimensions: Required[List[Optional[str]]] - """One or two event property values to evaluate matrix groups by""" + filters: Required[Iterable[NewFloatingBulkWithFiltersPriceBulkWithFiltersConfigFilter]] + """Property filters to apply (all must match)""" - matrix_values: Required[Iterable[NewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfigMatrixValue]] - """Matrix values for specified matrix grouping keys""" + tiers: Required[Iterable[NewFloatingBulkWithFiltersPriceBulkWithFiltersConfigTier]] + """Bulk tiers for rating based on total usage volume""" -class NewFloatingTieredPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +NewFloatingBulkWithFiltersPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingPackagePrice(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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["tiered"]] + model_type: Required[Literal["package"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - tiered_config: Required[NewFloatingTieredPriceTieredConfig] + package_config: Required[PackageConfig] + """Configuration for package pricing""" billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -303,6 +514,21 @@ class NewFloatingTieredPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingPackagePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -315,40 +541,45 @@ class NewFloatingTieredPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class NewFloatingTieredPriceTieredConfigTier(TypedDict, total=False): - first_unit: Required[float] - """Inclusive tier starting value""" + If unspecified, a single invoice is produced per billing cycle. + """ - unit_amount: Required[str] - """Amount per unit""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - last_unit: Optional[float] - """Exclusive tier ending value. If null, this is treated as the last tier""" + 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 NewFloatingTieredPriceTieredConfig(TypedDict, total=False): - tiers: Required[Iterable[NewFloatingTieredPriceTieredConfigTier]] - """Tiers for rating based on total usage quantities into the specified tier""" +NewFloatingPackagePriceConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] -class NewFloatingTieredBpsPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class NewFloatingMatrixPrice(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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["tiered_bps"]] + matrix_config: Required[MatrixConfig] + """Configuration for matrix pricing""" + + model_type: Required[Literal["matrix"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - tiered_bps_config: Required[NewFloatingTieredBpsPriceTieredBpsConfig] - billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -361,6 +592,21 @@ class NewFloatingTieredBpsPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingMatrixPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -373,46 +619,45 @@ class NewFloatingTieredBpsPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class NewFloatingTieredBpsPriceTieredBpsConfigTier(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""" + If unspecified, a single invoice is produced per billing cycle. + """ - per_unit_maximum: Optional[str] - """Per unit maximum to charge""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. -class NewFloatingTieredBpsPriceTieredBpsConfig(TypedDict, total=False): - tiers: Required[Iterable[NewFloatingTieredBpsPriceTieredBpsConfigTier]] - """ - Tiers for a Graduated BPS pricing model, where usage is bucketed into specified - tiers + 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 NewFloatingBpsPrice(TypedDict, total=False): - bps_config: Required[NewFloatingBpsPriceBpsConfig] +NewFloatingMatrixPriceConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] + +class NewFloatingThresholdTotalAmountPrice(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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["bps"]] + model_type: Required[Literal["threshold_total_amount"]] + """The pricing model type""" name: Required[str] """The name of the price.""" + threshold_total_amount_config: Required[NewFloatingThresholdTotalAmountPriceThresholdTotalAmountConfig] + """Configuration for threshold_total_amount pricing""" + billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -425,6 +670,21 @@ class NewFloatingBpsPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingThresholdTotalAmountPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -437,32 +697,71 @@ class NewFloatingBpsPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. -class NewFloatingBpsPriceBpsConfig(TypedDict, total=False): - bps: Required[float] - """Basis point take rate per event""" + 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 NewFloatingThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable(TypedDict, total=False): + """Configuration for a single threshold""" + + threshold: Required[str] + + total_amount: Required[str] + """Total amount for this threshold""" + + +class NewFloatingThresholdTotalAmountPriceThresholdTotalAmountConfig(TypedDict, total=False): + """Configuration for threshold_total_amount pricing""" + + consumption_table: Required[ + Iterable[NewFloatingThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable] + ] + """ + When the quantity consumed passes a provided threshold, the configured total + will be charged + """ - per_unit_maximum: Optional[str] - """Optional currency amount maximum to cap spend per event""" + prorate: Optional[bool] + """If true, the unit price will be prorated to the billing period""" -class NewFloatingBulkBpsPrice(TypedDict, total=False): - bulk_bps_config: Required[NewFloatingBulkBpsPriceBulkBpsConfig] +NewFloatingThresholdTotalAmountPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class NewFloatingTieredPackagePrice(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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["bulk_bps"]] + model_type: Required[Literal["tiered_package"]] + """The pricing model type""" name: Required[str] """The name of the price.""" + tiered_package_config: Required[NewFloatingTieredPackagePriceTieredPackageConfig] + """Configuration for tiered_package pricing""" + billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -475,6 +774,21 @@ class NewFloatingBulkBpsPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingTieredPackagePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -487,43 +801,70 @@ class NewFloatingBulkBpsPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class NewFloatingBulkBpsPriceBulkBpsConfigTier(TypedDict, total=False): - bps: Required[float] - """Basis points to rate on""" - - maximum_amount: Optional[str] - """Upper bound for tier""" + If unspecified, a single invoice is produced per billing cycle. + """ - per_unit_maximum: Optional[str] - """The maximum amount to charge for any one event""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. -class NewFloatingBulkBpsPriceBulkBpsConfig(TypedDict, total=False): - tiers: Required[Iterable[NewFloatingBulkBpsPriceBulkBpsConfigTier]] + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. """ - Tiers for a bulk BPS pricing model where all usage is aggregated to a single - tier based on total volume + + +class NewFloatingTieredPackagePriceTieredPackageConfigTier(TypedDict, total=False): + """Configuration for a single tier with business logic""" + + per_unit: Required[str] + """Price per package""" + + tier_lower_bound: Required[str] + + +class NewFloatingTieredPackagePriceTieredPackageConfig(TypedDict, total=False): + """Configuration for tiered_package pricing""" + + package_size: Required[str] + + tiers: Required[Iterable[NewFloatingTieredPackagePriceTieredPackageConfigTier]] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. The tier bounds are defined + based on the total quantity rather than the number of packages, so they must be + multiples of the package size. """ -class NewFloatingBulkPrice(TypedDict, total=False): - bulk_config: Required[NewFloatingBulkPriceBulkConfig] +NewFloatingTieredPackagePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class NewFloatingTieredWithMinimumPrice(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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["bulk"]] + model_type: Required[Literal["tiered_with_minimum"]] + """The pricing model type""" name: Required[str] """The name of the price.""" + tiered_with_minimum_config: Required[NewFloatingTieredWithMinimumPriceTieredWithMinimumConfig] + """Configuration for tiered_with_minimum pricing""" + billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -536,6 +877,21 @@ class NewFloatingBulkPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingTieredWithMinimumPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -548,37 +904,74 @@ class NewFloatingBulkPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingTieredWithMinimumPriceTieredWithMinimumConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + minimum_amount: Required[str] + + tier_lower_bound: Required[str] -class NewFloatingBulkPriceBulkConfigTier(TypedDict, total=False): unit_amount: Required[str] - """Amount per unit""" + """Per unit amount""" - maximum_units: Optional[float] - """Upper bound for this tier""" +class NewFloatingTieredWithMinimumPriceTieredWithMinimumConfig(TypedDict, total=False): + """Configuration for tiered_with_minimum pricing""" -class NewFloatingBulkPriceBulkConfig(TypedDict, total=False): - tiers: Required[Iterable[NewFloatingBulkPriceBulkConfigTier]] - """Bulk tiers for rating based on total usage volume""" + tiers: Required[Iterable[NewFloatingTieredWithMinimumPriceTieredWithMinimumConfigTier]] + """Tiered pricing with a minimum amount dependent on the volume tier. + + Tiers are defined using exclusive lower bounds. + """ + hide_zero_amount_tiers: bool + """If true, tiers with an accrued amount of 0 will not be included in the rating.""" -class NewFloatingThresholdTotalAmountPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] + prorate: bool + """If true, the unit price will be prorated to the billing period""" + + +NewFloatingTieredWithMinimumPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingGroupedTieredPrice(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_tiered_config: Required[NewFloatingGroupedTieredPriceGroupedTieredConfig] + """Configuration for grouped_tiered pricing""" + item_id: Required[str] - """The id of the item the plan will be associated with.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["threshold_total_amount"]] + model_type: Required[Literal["grouped_tiered"]] + """The pricing model type""" 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. @@ -591,6 +984,21 @@ class NewFloatingThresholdTotalAmountPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingGroupedTieredPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -603,65 +1011,68 @@ class NewFloatingThresholdTotalAmountPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class NewFloatingTieredPackagePrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] - """The cadence to bill for this price on.""" + If unspecified, a single invoice is produced per billing cycle. + """ - currency: Required[str] - """An ISO 4217 currency string for which this price is billed in.""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - item_id: Required[str] - """The id of the item the plan will be associated with.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - model_type: Required[Literal["tiered_package"]] + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - name: Required[str] - """The name of the price.""" - tiered_package_config: Required[Dict[str, object]] +class NewFloatingGroupedTieredPriceGroupedTieredConfigTier(TypedDict, total=False): + """Configuration for a single tier""" - billable_metric_id: Optional[str] - """The id of the billable metric for the price. + tier_lower_bound: Required[str] - Only needed if the price is usage-based. - """ + unit_amount: Required[str] + """Per unit amount""" - 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. - """ - external_price_id: Optional[str] - """An alias for the price.""" +class NewFloatingGroupedTieredPriceGroupedTieredConfig(TypedDict, total=False): + """Configuration for grouped_tiered pricing""" - fixed_price_quantity: Optional[float] + grouping_key: Required[str] + """The billable metric property used to group before tiering""" + + tiers: Required[Iterable[NewFloatingGroupedTieredPriceGroupedTieredConfigTier]] """ - If the Price represents a fixed cost, this represents the quantity of units - applied. + Apply tiered pricing to each segment generated after grouping with the provided + key """ - invoice_grouping_key: Optional[str] - """The property used to group this price on an invoice""" +NewFloatingGroupedTieredPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] -class NewFloatingTieredWithMinimumPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] + +class NewFloatingTieredPackageWithMinimumPrice(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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["tiered_with_minimum"]] + model_type: Required[Literal["tiered_package_with_minimum"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - tiered_with_minimum_config: Required[Dict[str, object]] + tiered_package_with_minimum_config: Required[NewFloatingTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig] + """Configuration for tiered_package_with_minimum pricing""" billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -675,6 +1086,21 @@ class NewFloatingTieredWithMinimumPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingTieredPackageWithMinimumPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -687,26 +1113,1915 @@ class NewFloatingTieredWithMinimumPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class NewFloatingPackageWithAllocationPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] - """The cadence to bill for this price on.""" + If unspecified, a single invoice is produced per billing cycle. + """ - currency: Required[str] - """An ISO 4217 currency string for which this price is billed in.""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - item_id: Required[str] - """The id of the item the plan will be associated with.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - model_type: Required[Literal["package_with_allocation"]] + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - name: Required[str] - """The name of the price.""" - package_with_allocation_config: Required[Dict[str, object]] +class NewFloatingTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier(TypedDict, total=False): + """Configuration for a single tier""" - billable_metric_id: Optional[str] - """The id of the billable metric for the price. + minimum_amount: Required[str] + + per_unit: Required[str] + + tier_lower_bound: Required[str] + + +class NewFloatingTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig(TypedDict, total=False): + """Configuration for tiered_package_with_minimum pricing""" + + package_size: Required[float] + + tiers: Required[Iterable[NewFloatingTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier]] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. + """ + + +NewFloatingTieredPackageWithMinimumPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingPackageWithAllocationPrice(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 price will be associated with.""" + + model_type: Required[Literal["package_with_allocation"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + package_with_allocation_config: Required[NewFloatingPackageWithAllocationPricePackageWithAllocationConfig] + """Configuration for package_with_allocation pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingPackageWithAllocationPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingPackageWithAllocationPricePackageWithAllocationConfig(TypedDict, total=False): + """Configuration for package_with_allocation pricing""" + + allocation: Required[str] + + package_amount: Required[str] + + package_size: Required[str] + + +NewFloatingPackageWithAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingUnitWithPercentPrice(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 price will be associated with.""" + + model_type: Required[Literal["unit_with_percent"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_with_percent_config: Required[NewFloatingUnitWithPercentPriceUnitWithPercentConfig] + """Configuration for unit_with_percent pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingUnitWithPercentPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingUnitWithPercentPriceUnitWithPercentConfig(TypedDict, total=False): + """Configuration for unit_with_percent pricing""" + + percent: Required[str] + """What percent, out of 100, of the calculated total to charge""" + + unit_amount: Required[str] + """Rate per unit of usage""" + + +NewFloatingUnitWithPercentPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingMatrixWithAllocationPrice(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 price will be associated with.""" + + matrix_with_allocation_config: Required[MatrixWithAllocationConfig] + """Configuration for matrix_with_allocation pricing""" + + model_type: Required[Literal["matrix_with_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingMatrixWithAllocationPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ + + +NewFloatingMatrixWithAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingMatrixWithThresholdDiscountsPrice(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 price will be associated with.""" + + matrix_with_threshold_discounts_config: Required[ + NewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + ] + """Configuration for matrix_with_threshold_discounts pricing""" + + model_type: Required[Literal["matrix_with_threshold_discounts"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue(TypedDict, total=False): + first_dimension_value: Required[str] + + unit_amount: Required[str] + + second_dimension_value: Optional[str] + + +class NewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup( + TypedDict, total=False +): + above_threshold_discount_percentage: Required[str] + """Discount rate applied to spend above the threshold.""" + + below_threshold_discount_percentage: Required[str] + """Discount rate applied to spend at or below the threshold. + + Set to 0 for no baseline discount. + """ + + cell_coordinates: Required[str] + """Semicolon-separated list of matrix cell coordinates targeted by this group. + + Each coordinate is `first,second` when the matrix has two dimensions, or just + `first` for a single-dimension matrix. Example: `blue,circle;green,triangle`. + """ + + threshold_amount: Required[str] + + description: Optional[str] + + +class NewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig(TypedDict, total=False): + """Configuration for matrix_with_threshold_discounts pricing""" + + default_unit_amount: Required[str] + """Unit price used for usage that does not match any defined matrix cell.""" + + first_dimension: Required[str] + """First matrix dimension key.""" + + matrix_values: Required[ + Iterable[NewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue] + ] + """Per-cell unit prices.""" + + second_dimension: Optional[str] + """Optional second matrix dimension key.""" + + threshold_discount_groups: Iterable[ + NewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup + ] + + +NewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingTieredWithProrationPrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered_with_proration"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_with_proration_config: Required[NewFloatingTieredWithProrationPriceTieredWithProrationConfig] + """Configuration for tiered_with_proration pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingTieredWithProrationPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingTieredWithProrationPriceTieredWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single tiered with proration tier""" + + tier_lower_bound: Required[str] + """Inclusive tier starting value""" + + unit_amount: Required[str] + """Amount per unit""" + + +class NewFloatingTieredWithProrationPriceTieredWithProrationConfig(TypedDict, total=False): + """Configuration for tiered_with_proration pricing""" + + tiers: Required[Iterable[NewFloatingTieredWithProrationPriceTieredWithProrationConfigTier]] + """ + Tiers for rating based on total usage quantities into the specified tier with + proration + """ + + +NewFloatingTieredWithProrationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingUnitWithProrationPrice(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 price will be associated with.""" + + model_type: Required[Literal["unit_with_proration"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_with_proration_config: Required[NewFloatingUnitWithProrationPriceUnitWithProrationConfig] + """Configuration for unit_with_proration pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingUnitWithProrationPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingUnitWithProrationPriceUnitWithProrationConfig(TypedDict, total=False): + """Configuration for unit_with_proration pricing""" + + unit_amount: Required[str] + """Rate per unit of usage""" + + +NewFloatingUnitWithProrationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingGroupedAllocationPrice(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_allocation_config: Required[NewFloatingGroupedAllocationPriceGroupedAllocationConfig] + """Configuration for grouped_allocation pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingGroupedAllocationPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingGroupedAllocationPriceGroupedAllocationConfig(TypedDict, total=False): + """Configuration for grouped_allocation pricing""" + + allocation: Required[str] + """Usage allocation per group""" + + grouping_key: Required[str] + """How to determine the groups that should each be allocated some quantity""" + + overage_unit_rate: Required[str] + """Unit rate for post-allocation""" + + +NewFloatingGroupedAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingBulkWithProrationPrice(TypedDict, total=False): + bulk_with_proration_config: Required[NewFloatingBulkWithProrationPriceBulkWithProrationConfig] + """Configuration for bulk_with_proration pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk_with_proration"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingBulkWithProrationPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingBulkWithProrationPriceBulkWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier with proration""" + + unit_amount: Required[str] + """Cost per unit""" + + tier_lower_bound: Optional[str] + """The lower bound for this tier""" + + +class NewFloatingBulkWithProrationPriceBulkWithProrationConfig(TypedDict, total=False): + """Configuration for bulk_with_proration pricing""" + + tiers: Required[Iterable[NewFloatingBulkWithProrationPriceBulkWithProrationConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +NewFloatingBulkWithProrationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingGroupedWithProratedMinimumPrice(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_prorated_minimum_config: Required[ + NewFloatingGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig + ] + """Configuration for grouped_with_prorated_minimum pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_prorated_minimum"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig(TypedDict, total=False): + """Configuration for grouped_with_prorated_minimum pricing""" + + grouping_key: Required[str] + """How to determine the groups that should each have a minimum""" + + minimum: Required[str] + """The minimum amount to charge per group""" + + unit_rate: Required[str] + """The amount to charge per unit""" + + +NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +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[ + NewFloatingGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig + ] + """Configuration for grouped_with_metered_minimum pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_metered_minimum"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor(TypedDict, total=False): + """Configuration for a scaling factor""" + + scaling_factor: Required[str] + + scaling_value: Required[str] + + +class NewFloatingGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount(TypedDict, total=False): + """Configuration for a unit amount""" + + pricing_value: Required[str] + + unit_amount: Required[str] + """Per unit amount""" + + +class NewFloatingGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig(TypedDict, total=False): + """Configuration for grouped_with_metered_minimum pricing""" + + grouping_key: Required[str] + """Used to partition the usage into groups. + + The minimum amount is applied to each group. + """ + + minimum_unit_amount: Required[str] + """The minimum amount to charge per group per unit""" + + pricing_key: Required[str] + """Used to determine the unit rate""" + + scaling_factors: Required[ + Iterable[NewFloatingGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor] + ] + """Scale the unit rates by the scaling factor.""" + + scaling_key: Required[str] + """Used to determine the unit rate scaling factor""" + + unit_amounts: Required[Iterable[NewFloatingGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount]] + """Apply per unit pricing to each pricing value. + + The minimum amount is applied any unmatched usage. + """ + + +NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingGroupedWithMinMaxThresholdsPrice(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_min_max_thresholds_config: Required[ + NewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + ] + """Configuration for grouped_with_min_max_thresholds pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_min_max_thresholds"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig(TypedDict, total=False): + """Configuration for grouped_with_min_max_thresholds pricing""" + + grouping_key: Required[str] + """The event property used to group before applying thresholds""" + + maximum_charge: Required[str] + """The maximum amount to charge each group""" + + minimum_charge: Required[str] + """The minimum amount to charge each group, regardless of usage""" + + per_unit_rate: Required[str] + """The base price charged per group""" + + +NewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +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 price will be associated with.""" + + matrix_with_display_name_config: Required[NewFloatingMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig] + """Configuration for matrix_with_display_name pricing""" + + model_type: Required[Literal["matrix_with_display_name"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingMatrixWithDisplayNamePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount(TypedDict, total=False): + """Configuration for a unit amount item""" + + dimension_value: Required[str] + """The dimension value""" + + display_name: Required[str] + """Display name for this dimension value""" + + unit_amount: Required[str] + """Per unit amount""" + + +class NewFloatingMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig(TypedDict, total=False): + """Configuration for matrix_with_display_name pricing""" + + dimension: Required[str] + """Used to determine the unit rate""" + + unit_amounts: Required[Iterable[NewFloatingMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount]] + """Apply per unit pricing to each dimension value""" + + +NewFloatingMatrixWithDisplayNamePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingGroupedTieredPackagePrice(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_tiered_package_config: Required[NewFloatingGroupedTieredPackagePriceGroupedTieredPackageConfig] + """Configuration for grouped_tiered_package pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_tiered_package"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingGroupedTieredPackagePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingGroupedTieredPackagePriceGroupedTieredPackageConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + per_unit: Required[str] + """Per package""" + + tier_lower_bound: Required[str] + + +class NewFloatingGroupedTieredPackagePriceGroupedTieredPackageConfig(TypedDict, total=False): + """Configuration for grouped_tiered_package pricing""" + + grouping_key: Required[str] + """The event property used to group before tiering""" + + package_size: Required[str] + + tiers: Required[Iterable[NewFloatingGroupedTieredPackagePriceGroupedTieredPackageConfigTier]] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. + """ + + +NewFloatingGroupedTieredPackagePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingMaxGroupTieredPackagePrice(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 price will be associated with.""" + + max_group_tiered_package_config: Required[NewFloatingMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig] + """Configuration for max_group_tiered_package pricing""" + + model_type: Required[Literal["max_group_tiered_package"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingMaxGroupTieredPackagePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + tier_lower_bound: Required[str] + + unit_amount: Required[str] + """Per unit amount""" + + +class NewFloatingMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig(TypedDict, total=False): + """Configuration for max_group_tiered_package pricing""" + + grouping_key: Required[str] + """ + The event property used to group before tiering the group with the highest value + """ + + package_size: Required[str] + + tiers: Required[Iterable[NewFloatingMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier]] + """Apply tiered pricing to the largest group after grouping with the provided key.""" + + +NewFloatingMaxGroupTieredPackagePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingScalableMatrixWithUnitPricingPrice(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 price will be associated with.""" + + model_type: Required[Literal["scalable_matrix_with_unit_pricing"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + scalable_matrix_with_unit_pricing_config: Required[ + NewFloatingScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig + ] + """Configuration for scalable_matrix_with_unit_pricing pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor( + TypedDict, total=False +): + """Configuration for a single matrix scaling factor""" + + first_dimension_value: Required[str] + + scaling_factor: Required[str] + + second_dimension_value: Optional[str] + + +class NewFloatingScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig(TypedDict, total=False): + """Configuration for scalable_matrix_with_unit_pricing pricing""" + + first_dimension: Required[str] + """Used to determine the unit rate""" + + matrix_scaling_factors: Required[ + Iterable[NewFloatingScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor] + ] + """Apply a scaling factor to each dimension""" + + unit_price: Required[str] + """The final unit price to rate against the output of the matrix""" + + grouping_key: Optional[str] + """The property used to group this price""" + + prorate: Optional[bool] + """If true, the unit price will be prorated to the billing period""" + + second_dimension: Optional[str] + """Used to determine the unit rate (optional)""" + + +NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingScalableMatrixWithTieredPricingPrice(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 price will be associated with.""" + + model_type: Required[Literal["scalable_matrix_with_tiered_pricing"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + scalable_matrix_with_tiered_pricing_config: Required[ + NewFloatingScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig + ] + """Configuration for scalable_matrix_with_tiered_pricing pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor( + TypedDict, total=False +): + """Configuration for a single matrix scaling factor""" + + first_dimension_value: Required[str] + + scaling_factor: Required[str] + + second_dimension_value: Optional[str] + + +class NewFloatingScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier(TypedDict, total=False): + """Configuration for a single tier entry with business logic""" + + tier_lower_bound: Required[str] + + unit_amount: Required[str] + + +class NewFloatingScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig(TypedDict, total=False): + """Configuration for scalable_matrix_with_tiered_pricing pricing""" + + first_dimension: Required[str] + """Used for the scalable matrix first dimension""" + + matrix_scaling_factors: Required[ + Iterable[ + NewFloatingScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor + ] + ] + """Apply a scaling factor to each dimension""" + + tiers: Required[Iterable[NewFloatingScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier]] + + second_dimension: Optional[str] + """Used for the scalable matrix second dimension (optional)""" + + +NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingCumulativeGroupedBulkPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_bulk_config: Required[NewFloatingCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig] + """Configuration for cumulative_grouped_bulk pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_bulk"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingCumulativeGroupedBulkPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue(TypedDict, total=False): + """Configuration for a dimension value entry""" + + grouping_key: Required[str] + """Grouping key value""" + + tier_lower_bound: Required[str] + """Tier lower bound""" + + unit_amount: Required[str] + """Unit amount for this combination""" + + +class NewFloatingCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig(TypedDict, total=False): + """Configuration for cumulative_grouped_bulk pricing""" + + dimension_values: Required[Iterable[NewFloatingCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue]] + """Each tier lower bound must have the same group of values.""" + + group: Required[str] + + +NewFloatingCumulativeGroupedBulkPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingCumulativeGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_allocation_config: Required[ + NewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + ] + """Configuration for cumulative_grouped_allocation pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingCumulativeGroupedAllocationPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig(TypedDict, total=False): + """Configuration for cumulative_grouped_allocation pricing""" + + cumulative_allocation: Required[str] + """The overall allocation across all groups""" + + group_allocation: Required[str] + """The allocation per individual group""" + + grouping_key: Required[str] + """The event property used to group usage before applying allocations""" + + unit_amount: Required[str] + """The amount to charge for each unit outside of the allocation""" + + +NewFloatingCumulativeGroupedAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingDailyCreditAllowancePrice(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.""" + + daily_credit_allowance_config: Required[NewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig] + """Configuration for daily_credit_allowance pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["daily_credit_allowance"]] + """The pricing model type""" + + 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. """ @@ -717,6 +3032,21 @@ class NewFloatingPackageWithAllocationPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingDailyCreditAllowancePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -729,23 +3059,199 @@ class NewFloatingPackageWithAllocationPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class NewFloatingTieredPackageWithMinimumPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue(TypedDict, total=False): + """Per-dimension credit price for the daily credit allowance model.""" + + dimension_values: Required[SequenceNotStr[Optional[str]]] + """One or two matrix keys to filter usage to this value by. + + For example, ["model"] could be used to apply a different credit rate to each AI + model. + """ + + unit_amount: Required[str] + """Credits charged per unit of usage matching the specified dimension_values""" + + +class NewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig(TypedDict, total=False): + """Configuration for daily_credit_allowance pricing""" + + daily_allowance: Required[str] + """Credits granted per day. Lose-it-or-use-it; does not roll over.""" + + default_unit_amount: Required[str] + """ + Default per-unit credit rate for any usage not bucketed into a specified + matrix_value + """ + + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" + + event_day_property: Required[str] + """Event property whose value identifies the day bucket the event belongs to (e.g. + + 'event_day' set to an ISO date string in the customer's timezone). The allowance + resets per distinct value of this property. + """ + + matrix_values: Required[Iterable[NewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue]] + """Per-dimension credit rates""" + + +NewFloatingDailyCreditAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingMeteredAllowancePrice(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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["tiered_package_with_minimum"]] + metered_allowance_config: Required[NewFloatingMeteredAllowancePriceMeteredAllowanceConfig] + """Configuration for metered_allowance pricing""" + + model_type: Required[Literal["metered_allowance"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - tiered_package_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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingMeteredAllowancePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingMeteredAllowancePriceMeteredAllowanceConfig(TypedDict, total=False): + """Configuration for metered_allowance pricing""" + + allowance_grouping_value: Required[str] + """ + The grouping_key value whose summed quantity represents the allowance for this + period (e.g. 'storage_snapshot' emitting 3 × avg storage). Capped at consumption + — credit can never exceed actual usage. + """ + + consumption_grouping_value: Required[str] + """The grouping_key value whose summed quantity represents consumption (e.g. + + 'download'). Charged at unit_amount. + """ + + grouping_key: Required[str] + """ + Event property used to partition the metric into consumption and allowance + quantities (e.g. 'event_name'). The metric is queried with this key and the two + values below select which partition is which. + """ + + unit_amount: Required[str] + """Per-unit price applied to gross consumption and to the allowance credit.""" + + allowance_display_name: str + """Sub-line label for the credit row (e.g. 'Up to 3x free egress').""" + + consumption_display_name: str + """Sub-line label for the gross consumption row (e.g. 'bytes gotten').""" + + +NewFloatingMeteredAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingMinimumCompositePrice(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 price will be associated with.""" + + minimum_composite_config: Required[NewFloatingMinimumCompositePriceMinimumCompositeConfig] + """Configuration for minimum_composite pricing""" + + model_type: Required[Literal["minimum_composite"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -759,6 +3265,21 @@ class NewFloatingTieredPackageWithMinimumPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingMinimumCompositePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -771,23 +3292,156 @@ class NewFloatingTieredPackageWithMinimumPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class NewFloatingUnitWithPercentPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingMinimumCompositePriceMinimumCompositeConfig(TypedDict, total=False): + """Configuration for minimum_composite pricing""" + + minimum_amount: Required[str] + """The minimum amount to apply""" + + prorated: bool + """If true, subtotals from this price are prorated based on the service period""" + + +NewFloatingMinimumCompositePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingPercentCompositePrice(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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["unit_with_percent"]] + model_type: Required[Literal["percent"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - unit_with_percent_config: Required[Dict[str, object]] + percent_config: Required[NewFloatingPercentCompositePricePercentConfig] + """Configuration for percent pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingPercentCompositePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingPercentCompositePricePercentConfig(TypedDict, total=False): + """Configuration for percent pricing""" + + percent: Required[float] + """Fraction of the component subtotals to charge (0 < percent <= 1).""" + + maximum_amount: Optional[str] + """Maximum amount to charge. If unset, the fee has no upper bound.""" + + minimum_amount: Optional[str] + """Minimum amount to charge. If unset, the fee is bounded below by 0.""" + + prorated: bool + """If true, the minimum_amount is prorated based on the service period. + + The maximum_amount is an absolute cap (never prorated), and the percent applied + to upstream subtotals is never prorated either. + """ + + +NewFloatingPercentCompositePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class NewFloatingEventOutputPrice(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.""" + + event_output_config: Required[NewFloatingEventOutputPriceEventOutputConfig] + """Configuration for event_output pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["event_output"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -801,6 +3455,21 @@ class NewFloatingUnitWithPercentPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[NewFloatingEventOutputPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -813,21 +3482,78 @@ class NewFloatingUnitWithPercentPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 NewFloatingEventOutputPriceEventOutputConfig(TypedDict, total=False): + """Configuration for event_output pricing""" + + unit_rating_key: Required[str] + """The key in the event data to extract the unit rate from.""" -PriceCreateParams = Union[ + default_unit_rate: Optional[str] + """ + If provided, this amount will be used as the unit rate when an event does not + have a value for the `unit_rating_key`. If not provided, events missing a unit + rate will be ignored. + """ + + grouping_key: Optional[str] + """An optional key in the event data to group by (e.g., event ID). + + All events will also be grouped by their unit rate. + """ + + +NewFloatingEventOutputPriceConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + +PriceCreateParams: TypeAlias = Union[ NewFloatingUnitPrice, - NewFloatingPackagePrice, - NewFloatingMatrixPrice, - NewFloatingMatrixWithAllocationPrice, NewFloatingTieredPrice, - NewFloatingTieredBpsPrice, - NewFloatingBpsPrice, - NewFloatingBulkBpsPrice, NewFloatingBulkPrice, + NewFloatingBulkWithFiltersPrice, + NewFloatingPackagePrice, + NewFloatingMatrixPrice, NewFloatingThresholdTotalAmountPrice, NewFloatingTieredPackagePrice, NewFloatingTieredWithMinimumPrice, - NewFloatingPackageWithAllocationPrice, + NewFloatingGroupedTieredPrice, NewFloatingTieredPackageWithMinimumPrice, + NewFloatingPackageWithAllocationPrice, NewFloatingUnitWithPercentPrice, + NewFloatingMatrixWithAllocationPrice, + NewFloatingMatrixWithThresholdDiscountsPrice, + NewFloatingTieredWithProrationPrice, + NewFloatingUnitWithProrationPrice, + NewFloatingGroupedAllocationPrice, + NewFloatingBulkWithProrationPrice, + NewFloatingGroupedWithProratedMinimumPrice, + NewFloatingGroupedWithMeteredMinimumPrice, + NewFloatingGroupedWithMinMaxThresholdsPrice, + NewFloatingMatrixWithDisplayNamePrice, + NewFloatingGroupedTieredPackagePrice, + NewFloatingMaxGroupTieredPackagePrice, + NewFloatingScalableMatrixWithUnitPricingPrice, + NewFloatingScalableMatrixWithTieredPricingPrice, + NewFloatingCumulativeGroupedBulkPrice, + NewFloatingCumulativeGroupedAllocationPrice, + NewFloatingDailyCreditAllowancePrice, + NewFloatingMeteredAllowancePrice, + NewFloatingMinimumCompositePrice, + NewFloatingPercentCompositePrice, + NewFloatingEventOutputPrice, ] diff --git a/src/orb/types/price_evaluate_multiple_params.py b/src/orb/types/price_evaluate_multiple_params.py new file mode 100644 index 00000000..f248a68f --- /dev/null +++ b/src/orb/types/price_evaluate_multiple_params.py @@ -0,0 +1,1063 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .._utils import PropertyInfo +from .shared_params.new_floating_bulk_price import NewFloatingBulkPrice +from .shared_params.new_floating_unit_price import NewFloatingUnitPrice +from .shared_params.new_floating_matrix_price import NewFloatingMatrixPrice +from .shared_params.new_floating_tiered_price import NewFloatingTieredPrice +from .shared_params.new_floating_package_price import NewFloatingPackagePrice +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_floating_grouped_tiered_price import NewFloatingGroupedTieredPrice +from .shared_params.new_floating_tiered_package_price import NewFloatingTieredPackagePrice +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration +from .shared_params.new_floating_minimum_composite_price import NewFloatingMinimumCompositePrice +from .shared_params.new_floating_unit_with_percent_price import NewFloatingUnitWithPercentPrice +from .shared_params.new_floating_grouped_allocation_price import NewFloatingGroupedAllocationPrice +from .shared_params.new_floating_bulk_with_proration_price import NewFloatingBulkWithProrationPrice +from .shared_params.new_floating_tiered_with_minimum_price import NewFloatingTieredWithMinimumPrice +from .shared_params.new_floating_unit_with_proration_price import NewFloatingUnitWithProrationPrice +from .shared_params.new_floating_tiered_with_proration_price import NewFloatingTieredWithProrationPrice +from .shared_params.new_floating_grouped_tiered_package_price import NewFloatingGroupedTieredPackagePrice +from .shared_params.new_floating_matrix_with_allocation_price import NewFloatingMatrixWithAllocationPrice +from .shared_params.new_floating_threshold_total_amount_price import NewFloatingThresholdTotalAmountPrice +from .shared_params.new_floating_cumulative_grouped_bulk_price import NewFloatingCumulativeGroupedBulkPrice +from .shared_params.new_floating_package_with_allocation_price import NewFloatingPackageWithAllocationPrice +from .shared_params.new_floating_matrix_with_display_name_price import NewFloatingMatrixWithDisplayNamePrice +from .shared_params.new_floating_max_group_tiered_package_price import NewFloatingMaxGroupTieredPackagePrice +from .shared_params.new_floating_tiered_package_with_minimum_price import NewFloatingTieredPackageWithMinimumPrice +from .shared_params.new_floating_grouped_with_metered_minimum_price import NewFloatingGroupedWithMeteredMinimumPrice +from .shared_params.new_floating_grouped_with_prorated_minimum_price import NewFloatingGroupedWithProratedMinimumPrice +from .shared_params.new_floating_scalable_matrix_with_unit_pricing_price import ( + NewFloatingScalableMatrixWithUnitPricingPrice, +) +from .shared_params.new_floating_scalable_matrix_with_tiered_pricing_price import ( + NewFloatingScalableMatrixWithTieredPricingPrice, +) + +__all__ = [ + "PriceEvaluateMultipleParams", + "PriceEvaluation", + "PriceEvaluationPrice", + "PriceEvaluationPriceNewFloatingBulkWithFiltersPrice", + "PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfig", + "PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigFilter", + "PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigTier", + "PriceEvaluationPriceNewFloatingBulkWithFiltersPriceConversionRateConfig", + "PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPrice", + "PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig", + "PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue", + "PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup", + "PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig", + "PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPrice", + "PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig", + "PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig", + "PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPrice", + "PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig", + "PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPriceConversionRateConfig", + "PriceEvaluationPriceNewFloatingDailyCreditAllowancePrice", + "PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig", + "PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue", + "PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceConversionRateConfig", + "PriceEvaluationPriceNewFloatingMeteredAllowancePrice", + "PriceEvaluationPriceNewFloatingMeteredAllowancePriceMeteredAllowanceConfig", + "PriceEvaluationPriceNewFloatingMeteredAllowancePriceConversionRateConfig", + "PriceEvaluationPriceNewFloatingPercentCompositePrice", + "PriceEvaluationPriceNewFloatingPercentCompositePricePercentConfig", + "PriceEvaluationPriceNewFloatingPercentCompositePriceConversionRateConfig", + "PriceEvaluationPriceNewFloatingEventOutputPrice", + "PriceEvaluationPriceNewFloatingEventOutputPriceEventOutputConfig", + "PriceEvaluationPriceNewFloatingEventOutputPriceConversionRateConfig", +] + + +class PriceEvaluateMultipleParams(TypedDict, total=False): + timeframe_end: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """The exclusive upper bound for event timestamps""" + + timeframe_start: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """The inclusive lower bound for event timestamps""" + + customer_id: Optional[str] + """The ID of the customer to which this evaluation is scoped.""" + + external_customer_id: Optional[str] + """The external customer ID of the customer to which this evaluation is scoped.""" + + price_evaluations: Iterable[PriceEvaluation] + """List of prices to evaluate (max 100)""" + + +class PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigFilter(TypedDict, total=False): + """Configuration for a single property filter""" + + property_key: Required[str] + """Event property key to filter on""" + + property_value: Required[str] + """Event property value to match""" + + +class PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier""" + + unit_amount: Required[str] + """Amount per unit""" + + tier_lower_bound: Optional[str] + """The lower bound for this tier""" + + +class PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfig(TypedDict, total=False): + """Configuration for bulk_with_filters pricing""" + + filters: Required[Iterable[PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigFilter]] + """Property filters to apply (all must match)""" + + tiers: Required[Iterable[PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +PriceEvaluationPriceNewFloatingBulkWithFiltersPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingBulkWithFiltersPrice(TypedDict, total=False): + bulk_with_filters_config: Required[PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfig] + """Configuration for bulk_with_filters pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk_with_filters"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PriceEvaluationPriceNewFloatingBulkWithFiltersPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue( + TypedDict, total=False +): + first_dimension_value: Required[str] + + unit_amount: Required[str] + + second_dimension_value: Optional[str] + + +class PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup( + TypedDict, total=False +): + above_threshold_discount_percentage: Required[str] + """Discount rate applied to spend above the threshold.""" + + below_threshold_discount_percentage: Required[str] + """Discount rate applied to spend at or below the threshold. + + Set to 0 for no baseline discount. + """ + + cell_coordinates: Required[str] + """Semicolon-separated list of matrix cell coordinates targeted by this group. + + Each coordinate is `first,second` when the matrix has two dimensions, or just + `first` for a single-dimension matrix. Example: `blue,circle;green,triangle`. + """ + + threshold_amount: Required[str] + + description: Optional[str] + + +class PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig( + TypedDict, total=False +): + """Configuration for matrix_with_threshold_discounts pricing""" + + default_unit_amount: Required[str] + """Unit price used for usage that does not match any defined matrix cell.""" + + first_dimension: Required[str] + """First matrix dimension key.""" + + matrix_values: Required[ + Iterable[ + PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue + ] + ] + """Per-cell unit prices.""" + + second_dimension: Optional[str] + """Optional second matrix dimension key.""" + + threshold_discount_groups: Iterable[ + PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup + ] + + +PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPrice(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 price will be associated with.""" + + matrix_with_threshold_discounts_config: Required[ + PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + ] + """Configuration for matrix_with_threshold_discounts pricing""" + + model_type: Required[Literal["matrix_with_threshold_discounts"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ + PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig + ] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig( + TypedDict, total=False +): + """Configuration for grouped_with_min_max_thresholds pricing""" + + grouping_key: Required[str] + """The event property used to group before applying thresholds""" + + maximum_charge: Required[str] + """The maximum amount to charge each group""" + + minimum_charge: Required[str] + """The minimum amount to charge each group, regardless of usage""" + + per_unit_rate: Required[str] + """The base price charged per group""" + + +PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPrice(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_min_max_thresholds_config: Required[ + PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + ] + """Configuration for grouped_with_min_max_thresholds pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_min_max_thresholds"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ + PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig + ] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig( + TypedDict, total=False +): + """Configuration for cumulative_grouped_allocation pricing""" + + cumulative_allocation: Required[str] + """The overall allocation across all groups""" + + group_allocation: Required[str] + """The allocation per individual group""" + + grouping_key: Required[str] + """The event property used to group usage before applying allocations""" + + unit_amount: Required[str] + """The amount to charge for each unit outside of the allocation""" + + +PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_allocation_config: Required[ + PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + ] + """Configuration for cumulative_grouped_allocation pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ + PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPriceConversionRateConfig + ] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue( + TypedDict, total=False +): + """Per-dimension credit price for the daily credit allowance model.""" + + dimension_values: Required[SequenceNotStr[Optional[str]]] + """One or two matrix keys to filter usage to this value by. + + For example, ["model"] could be used to apply a different credit rate to each AI + model. + """ + + unit_amount: Required[str] + """Credits charged per unit of usage matching the specified dimension_values""" + + +class PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig(TypedDict, total=False): + """Configuration for daily_credit_allowance pricing""" + + daily_allowance: Required[str] + """Credits granted per day. Lose-it-or-use-it; does not roll over.""" + + default_unit_amount: Required[str] + """ + Default per-unit credit rate for any usage not bucketed into a specified + matrix_value + """ + + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" + + event_day_property: Required[str] + """Event property whose value identifies the day bucket the event belongs to (e.g. + + 'event_day' set to an ISO date string in the customer's timezone). The allowance + resets per distinct value of this property. + """ + + matrix_values: Required[ + Iterable[PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue] + ] + """Per-dimension credit rates""" + + +PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingDailyCreditAllowancePrice(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.""" + + daily_credit_allowance_config: Required[ + PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig + ] + """Configuration for daily_credit_allowance pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["daily_credit_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceEvaluationPriceNewFloatingMeteredAllowancePriceMeteredAllowanceConfig(TypedDict, total=False): + """Configuration for metered_allowance pricing""" + + allowance_grouping_value: Required[str] + """ + The grouping_key value whose summed quantity represents the allowance for this + period (e.g. 'storage_snapshot' emitting 3 × avg storage). Capped at consumption + — credit can never exceed actual usage. + """ + + consumption_grouping_value: Required[str] + """The grouping_key value whose summed quantity represents consumption (e.g. + + 'download'). Charged at unit_amount. + """ + + grouping_key: Required[str] + """ + Event property used to partition the metric into consumption and allowance + quantities (e.g. 'event_name'). The metric is queried with this key and the two + values below select which partition is which. + """ + + unit_amount: Required[str] + """Per-unit price applied to gross consumption and to the allowance credit.""" + + allowance_display_name: str + """Sub-line label for the credit row (e.g. 'Up to 3x free egress').""" + + consumption_display_name: str + """Sub-line label for the gross consumption row (e.g. 'bytes gotten').""" + + +PriceEvaluationPriceNewFloatingMeteredAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingMeteredAllowancePrice(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 price will be associated with.""" + + metered_allowance_config: Required[PriceEvaluationPriceNewFloatingMeteredAllowancePriceMeteredAllowanceConfig] + """Configuration for metered_allowance pricing""" + + model_type: Required[Literal["metered_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PriceEvaluationPriceNewFloatingMeteredAllowancePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceEvaluationPriceNewFloatingPercentCompositePricePercentConfig(TypedDict, total=False): + """Configuration for percent pricing""" + + percent: Required[float] + """Fraction of the component subtotals to charge (0 < percent <= 1).""" + + maximum_amount: Optional[str] + """Maximum amount to charge. If unset, the fee has no upper bound.""" + + minimum_amount: Optional[str] + """Minimum amount to charge. If unset, the fee is bounded below by 0.""" + + prorated: bool + """If true, the minimum_amount is prorated based on the service period. + + The maximum_amount is an absolute cap (never prorated), and the percent applied + to upstream subtotals is never prorated either. + """ + + +PriceEvaluationPriceNewFloatingPercentCompositePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingPercentCompositePrice(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 price will be associated with.""" + + model_type: Required[Literal["percent"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + percent_config: Required[PriceEvaluationPriceNewFloatingPercentCompositePricePercentConfig] + """Configuration for percent pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PriceEvaluationPriceNewFloatingPercentCompositePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceEvaluationPriceNewFloatingEventOutputPriceEventOutputConfig(TypedDict, total=False): + """Configuration for event_output pricing""" + + unit_rating_key: Required[str] + """The key in the event data to extract the unit rate from.""" + + default_unit_rate: Optional[str] + """ + If provided, this amount will be used as the unit rate when an event does not + have a value for the `unit_rating_key`. If not provided, events missing a unit + rate will be ignored. + """ + + grouping_key: Optional[str] + """An optional key in the event data to group by (e.g., event ID). + + All events will also be grouped by their unit rate. + """ + + +PriceEvaluationPriceNewFloatingEventOutputPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingEventOutputPrice(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.""" + + event_output_config: Required[PriceEvaluationPriceNewFloatingEventOutputPriceEventOutputConfig] + """Configuration for event_output pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["event_output"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PriceEvaluationPriceNewFloatingEventOutputPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ + + +PriceEvaluationPrice: TypeAlias = Union[ + NewFloatingUnitPrice, + NewFloatingTieredPrice, + NewFloatingBulkPrice, + PriceEvaluationPriceNewFloatingBulkWithFiltersPrice, + NewFloatingPackagePrice, + NewFloatingMatrixPrice, + NewFloatingThresholdTotalAmountPrice, + NewFloatingTieredPackagePrice, + NewFloatingTieredWithMinimumPrice, + NewFloatingGroupedTieredPrice, + NewFloatingTieredPackageWithMinimumPrice, + NewFloatingPackageWithAllocationPrice, + NewFloatingUnitWithPercentPrice, + NewFloatingMatrixWithAllocationPrice, + PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPrice, + NewFloatingTieredWithProrationPrice, + NewFloatingUnitWithProrationPrice, + NewFloatingGroupedAllocationPrice, + NewFloatingBulkWithProrationPrice, + NewFloatingGroupedWithProratedMinimumPrice, + NewFloatingGroupedWithMeteredMinimumPrice, + PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPrice, + NewFloatingMatrixWithDisplayNamePrice, + NewFloatingGroupedTieredPackagePrice, + NewFloatingMaxGroupTieredPackagePrice, + NewFloatingScalableMatrixWithUnitPricingPrice, + NewFloatingScalableMatrixWithTieredPricingPrice, + NewFloatingCumulativeGroupedBulkPrice, + PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPrice, + PriceEvaluationPriceNewFloatingDailyCreditAllowancePrice, + PriceEvaluationPriceNewFloatingMeteredAllowancePrice, + NewFloatingMinimumCompositePrice, + PriceEvaluationPriceNewFloatingPercentCompositePrice, + PriceEvaluationPriceNewFloatingEventOutputPrice, +] + + +class PriceEvaluation(TypedDict, total=False): + external_price_id: Optional[str] + """The external ID of a price to evaluate that exists in your Orb account.""" + + filter: Optional[str] + """ + A boolean + [computed property](/extensibility/advanced-metrics#computed-properties) used to + filter the underlying billable metric + """ + + grouping_keys: SequenceNotStr[str] + """ + Properties (or + [computed properties](/extensibility/advanced-metrics#computed-properties)) used + to group the underlying billable metric + """ + + metric_parameter_overrides: Optional[Dict[str, object]] + """Optional overrides for parameterized billable metric parameters. + + If the metric has parameter definitions and no overrides are provided, defaults + will be used. + """ + + price: Optional[PriceEvaluationPrice] + """New floating price request body params.""" + + price_id: Optional[str] + """The ID of a price to evaluate that exists in your Orb account.""" diff --git a/src/orb/types/price_evaluate_multiple_response.py b/src/orb/types/price_evaluate_multiple_response.py new file mode 100644 index 00000000..98d435c9 --- /dev/null +++ b/src/orb/types/price_evaluate_multiple_response.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel +from .evaluate_price_group import EvaluatePriceGroup + +__all__ = ["PriceEvaluateMultipleResponse", "Data"] + + +class Data(BaseModel): + currency: str + """The currency of the price""" + + price_groups: List[EvaluatePriceGroup] + """The computed price groups associated with input price.""" + + external_price_id: Optional[str] = None + """The external ID of the price""" + + inline_price_index: Optional[int] = None + """The index of the inline price""" + + price_id: Optional[str] = None + """The ID of the price""" + + +class PriceEvaluateMultipleResponse(BaseModel): + data: List[Data] diff --git a/src/orb/types/beta/price_evaluate_params.py b/src/orb/types/price_evaluate_params.py similarity index 58% rename from src/orb/types/beta/price_evaluate_params.py rename to src/orb/types/price_evaluate_params.py index c0fb00f3..4e508f11 100644 --- a/src/orb/types/beta/price_evaluate_params.py +++ b/src/orb/types/price_evaluate_params.py @@ -2,11 +2,12 @@ from __future__ import annotations -from typing import List, Union, Optional +from typing import Dict, Union, Optional from datetime import datetime from typing_extensions import Required, Annotated, TypedDict -from ..._utils import PropertyInfo +from .._types import SequenceNotStr +from .._utils import PropertyInfo __all__ = ["PriceEvaluateParams"] @@ -27,13 +28,20 @@ class PriceEvaluateParams(TypedDict, total=False): filter: Optional[str] """ A boolean - [computed property](../guides/extensibility/advanced-metrics#computed-properties) - used to filter the underlying billable metric + [computed property](/extensibility/advanced-metrics#computed-properties) used to + filter the underlying billable metric """ - grouping_keys: List[str] + grouping_keys: SequenceNotStr[str] """ Properties (or - [computed properties](../guides/extensibility/advanced-metrics#computed-properties)) - used to group the underlying billable metric + [computed properties](/extensibility/advanced-metrics#computed-properties)) used + to group the underlying billable metric + """ + + metric_parameter_overrides: Optional[Dict[str, object]] + """Optional overrides for parameterized billable metric parameters. + + If the metric has parameter definitions and no overrides are provided, defaults + will be used. """ diff --git a/src/orb/types/price_evaluate_preview_events_params.py b/src/orb/types/price_evaluate_preview_events_params.py new file mode 100644 index 00000000..62d31035 --- /dev/null +++ b/src/orb/types/price_evaluate_preview_events_params.py @@ -0,0 +1,1095 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .._utils import PropertyInfo +from .shared_params.new_floating_bulk_price import NewFloatingBulkPrice +from .shared_params.new_floating_unit_price import NewFloatingUnitPrice +from .shared_params.new_floating_matrix_price import NewFloatingMatrixPrice +from .shared_params.new_floating_tiered_price import NewFloatingTieredPrice +from .shared_params.new_floating_package_price import NewFloatingPackagePrice +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_floating_grouped_tiered_price import NewFloatingGroupedTieredPrice +from .shared_params.new_floating_tiered_package_price import NewFloatingTieredPackagePrice +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration +from .shared_params.new_floating_minimum_composite_price import NewFloatingMinimumCompositePrice +from .shared_params.new_floating_unit_with_percent_price import NewFloatingUnitWithPercentPrice +from .shared_params.new_floating_grouped_allocation_price import NewFloatingGroupedAllocationPrice +from .shared_params.new_floating_bulk_with_proration_price import NewFloatingBulkWithProrationPrice +from .shared_params.new_floating_tiered_with_minimum_price import NewFloatingTieredWithMinimumPrice +from .shared_params.new_floating_unit_with_proration_price import NewFloatingUnitWithProrationPrice +from .shared_params.new_floating_tiered_with_proration_price import NewFloatingTieredWithProrationPrice +from .shared_params.new_floating_grouped_tiered_package_price import NewFloatingGroupedTieredPackagePrice +from .shared_params.new_floating_matrix_with_allocation_price import NewFloatingMatrixWithAllocationPrice +from .shared_params.new_floating_threshold_total_amount_price import NewFloatingThresholdTotalAmountPrice +from .shared_params.new_floating_cumulative_grouped_bulk_price import NewFloatingCumulativeGroupedBulkPrice +from .shared_params.new_floating_package_with_allocation_price import NewFloatingPackageWithAllocationPrice +from .shared_params.new_floating_matrix_with_display_name_price import NewFloatingMatrixWithDisplayNamePrice +from .shared_params.new_floating_max_group_tiered_package_price import NewFloatingMaxGroupTieredPackagePrice +from .shared_params.new_floating_tiered_package_with_minimum_price import NewFloatingTieredPackageWithMinimumPrice +from .shared_params.new_floating_grouped_with_metered_minimum_price import NewFloatingGroupedWithMeteredMinimumPrice +from .shared_params.new_floating_grouped_with_prorated_minimum_price import NewFloatingGroupedWithProratedMinimumPrice +from .shared_params.new_floating_scalable_matrix_with_unit_pricing_price import ( + NewFloatingScalableMatrixWithUnitPricingPrice, +) +from .shared_params.new_floating_scalable_matrix_with_tiered_pricing_price import ( + NewFloatingScalableMatrixWithTieredPricingPrice, +) + +__all__ = [ + "PriceEvaluatePreviewEventsParams", + "Event", + "PriceEvaluation", + "PriceEvaluationPrice", + "PriceEvaluationPriceNewFloatingBulkWithFiltersPrice", + "PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfig", + "PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigFilter", + "PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigTier", + "PriceEvaluationPriceNewFloatingBulkWithFiltersPriceConversionRateConfig", + "PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPrice", + "PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig", + "PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue", + "PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup", + "PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig", + "PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPrice", + "PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig", + "PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig", + "PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPrice", + "PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig", + "PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPriceConversionRateConfig", + "PriceEvaluationPriceNewFloatingDailyCreditAllowancePrice", + "PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig", + "PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue", + "PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceConversionRateConfig", + "PriceEvaluationPriceNewFloatingMeteredAllowancePrice", + "PriceEvaluationPriceNewFloatingMeteredAllowancePriceMeteredAllowanceConfig", + "PriceEvaluationPriceNewFloatingMeteredAllowancePriceConversionRateConfig", + "PriceEvaluationPriceNewFloatingPercentCompositePrice", + "PriceEvaluationPriceNewFloatingPercentCompositePricePercentConfig", + "PriceEvaluationPriceNewFloatingPercentCompositePriceConversionRateConfig", + "PriceEvaluationPriceNewFloatingEventOutputPrice", + "PriceEvaluationPriceNewFloatingEventOutputPriceEventOutputConfig", + "PriceEvaluationPriceNewFloatingEventOutputPriceConversionRateConfig", +] + + +class PriceEvaluatePreviewEventsParams(TypedDict, total=False): + timeframe_end: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """The exclusive upper bound for event timestamps""" + + timeframe_start: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """The inclusive lower bound for event timestamps""" + + customer_id: Optional[str] + """The ID of the customer to which this evaluation is scoped.""" + + events: Iterable[Event] + """List of preview events to use instead of actual usage data""" + + external_customer_id: Optional[str] + """The external customer ID of the customer to which this evaluation is scoped.""" + + price_evaluations: Iterable[PriceEvaluation] + """List of prices to evaluate (max 100)""" + + +class Event(TypedDict, total=False): + event_name: Required[str] + """A name to meaningfully identify the action or event type.""" + + properties: Required[Dict[str, object]] + """A dictionary of custom properties. + + Values in this dictionary must be numeric, boolean, or strings. Nested + dictionaries are disallowed. + """ + + timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """An ISO 8601 format date with no timezone offset (i.e. + + UTC). This should represent the time that usage was recorded, and is + particularly important to attribute usage to a given billing period. + """ + + customer_id: Optional[str] + """The Orb Customer identifier""" + + external_customer_id: Optional[str] + """ + An alias for the Orb customer, whose mapping is specified when creating the + customer + """ + + +class PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigFilter(TypedDict, total=False): + """Configuration for a single property filter""" + + property_key: Required[str] + """Event property key to filter on""" + + property_value: Required[str] + """Event property value to match""" + + +class PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier""" + + unit_amount: Required[str] + """Amount per unit""" + + tier_lower_bound: Optional[str] + """The lower bound for this tier""" + + +class PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfig(TypedDict, total=False): + """Configuration for bulk_with_filters pricing""" + + filters: Required[Iterable[PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigFilter]] + """Property filters to apply (all must match)""" + + tiers: Required[Iterable[PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +PriceEvaluationPriceNewFloatingBulkWithFiltersPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingBulkWithFiltersPrice(TypedDict, total=False): + bulk_with_filters_config: Required[PriceEvaluationPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfig] + """Configuration for bulk_with_filters pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk_with_filters"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PriceEvaluationPriceNewFloatingBulkWithFiltersPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue( + TypedDict, total=False +): + first_dimension_value: Required[str] + + unit_amount: Required[str] + + second_dimension_value: Optional[str] + + +class PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup( + TypedDict, total=False +): + above_threshold_discount_percentage: Required[str] + """Discount rate applied to spend above the threshold.""" + + below_threshold_discount_percentage: Required[str] + """Discount rate applied to spend at or below the threshold. + + Set to 0 for no baseline discount. + """ + + cell_coordinates: Required[str] + """Semicolon-separated list of matrix cell coordinates targeted by this group. + + Each coordinate is `first,second` when the matrix has two dimensions, or just + `first` for a single-dimension matrix. Example: `blue,circle;green,triangle`. + """ + + threshold_amount: Required[str] + + description: Optional[str] + + +class PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig( + TypedDict, total=False +): + """Configuration for matrix_with_threshold_discounts pricing""" + + default_unit_amount: Required[str] + """Unit price used for usage that does not match any defined matrix cell.""" + + first_dimension: Required[str] + """First matrix dimension key.""" + + matrix_values: Required[ + Iterable[ + PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue + ] + ] + """Per-cell unit prices.""" + + second_dimension: Optional[str] + """Optional second matrix dimension key.""" + + threshold_discount_groups: Iterable[ + PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup + ] + + +PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPrice(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 price will be associated with.""" + + matrix_with_threshold_discounts_config: Required[ + PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + ] + """Configuration for matrix_with_threshold_discounts pricing""" + + model_type: Required[Literal["matrix_with_threshold_discounts"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ + PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig + ] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig( + TypedDict, total=False +): + """Configuration for grouped_with_min_max_thresholds pricing""" + + grouping_key: Required[str] + """The event property used to group before applying thresholds""" + + maximum_charge: Required[str] + """The maximum amount to charge each group""" + + minimum_charge: Required[str] + """The minimum amount to charge each group, regardless of usage""" + + per_unit_rate: Required[str] + """The base price charged per group""" + + +PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPrice(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_min_max_thresholds_config: Required[ + PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + ] + """Configuration for grouped_with_min_max_thresholds pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_min_max_thresholds"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ + PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig + ] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig( + TypedDict, total=False +): + """Configuration for cumulative_grouped_allocation pricing""" + + cumulative_allocation: Required[str] + """The overall allocation across all groups""" + + group_allocation: Required[str] + """The allocation per individual group""" + + grouping_key: Required[str] + """The event property used to group usage before applying allocations""" + + unit_amount: Required[str] + """The amount to charge for each unit outside of the allocation""" + + +PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_allocation_config: Required[ + PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + ] + """Configuration for cumulative_grouped_allocation pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ + PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPriceConversionRateConfig + ] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue( + TypedDict, total=False +): + """Per-dimension credit price for the daily credit allowance model.""" + + dimension_values: Required[SequenceNotStr[Optional[str]]] + """One or two matrix keys to filter usage to this value by. + + For example, ["model"] could be used to apply a different credit rate to each AI + model. + """ + + unit_amount: Required[str] + """Credits charged per unit of usage matching the specified dimension_values""" + + +class PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig(TypedDict, total=False): + """Configuration for daily_credit_allowance pricing""" + + daily_allowance: Required[str] + """Credits granted per day. Lose-it-or-use-it; does not roll over.""" + + default_unit_amount: Required[str] + """ + Default per-unit credit rate for any usage not bucketed into a specified + matrix_value + """ + + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" + + event_day_property: Required[str] + """Event property whose value identifies the day bucket the event belongs to (e.g. + + 'event_day' set to an ISO date string in the customer's timezone). The allowance + resets per distinct value of this property. + """ + + matrix_values: Required[ + Iterable[PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue] + ] + """Per-dimension credit rates""" + + +PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingDailyCreditAllowancePrice(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.""" + + daily_credit_allowance_config: Required[ + PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig + ] + """Configuration for daily_credit_allowance pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["daily_credit_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PriceEvaluationPriceNewFloatingDailyCreditAllowancePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceEvaluationPriceNewFloatingMeteredAllowancePriceMeteredAllowanceConfig(TypedDict, total=False): + """Configuration for metered_allowance pricing""" + + allowance_grouping_value: Required[str] + """ + The grouping_key value whose summed quantity represents the allowance for this + period (e.g. 'storage_snapshot' emitting 3 × avg storage). Capped at consumption + — credit can never exceed actual usage. + """ + + consumption_grouping_value: Required[str] + """The grouping_key value whose summed quantity represents consumption (e.g. + + 'download'). Charged at unit_amount. + """ + + grouping_key: Required[str] + """ + Event property used to partition the metric into consumption and allowance + quantities (e.g. 'event_name'). The metric is queried with this key and the two + values below select which partition is which. + """ + + unit_amount: Required[str] + """Per-unit price applied to gross consumption and to the allowance credit.""" + + allowance_display_name: str + """Sub-line label for the credit row (e.g. 'Up to 3x free egress').""" + + consumption_display_name: str + """Sub-line label for the gross consumption row (e.g. 'bytes gotten').""" + + +PriceEvaluationPriceNewFloatingMeteredAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingMeteredAllowancePrice(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 price will be associated with.""" + + metered_allowance_config: Required[PriceEvaluationPriceNewFloatingMeteredAllowancePriceMeteredAllowanceConfig] + """Configuration for metered_allowance pricing""" + + model_type: Required[Literal["metered_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PriceEvaluationPriceNewFloatingMeteredAllowancePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceEvaluationPriceNewFloatingPercentCompositePricePercentConfig(TypedDict, total=False): + """Configuration for percent pricing""" + + percent: Required[float] + """Fraction of the component subtotals to charge (0 < percent <= 1).""" + + maximum_amount: Optional[str] + """Maximum amount to charge. If unset, the fee has no upper bound.""" + + minimum_amount: Optional[str] + """Minimum amount to charge. If unset, the fee is bounded below by 0.""" + + prorated: bool + """If true, the minimum_amount is prorated based on the service period. + + The maximum_amount is an absolute cap (never prorated), and the percent applied + to upstream subtotals is never prorated either. + """ + + +PriceEvaluationPriceNewFloatingPercentCompositePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingPercentCompositePrice(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 price will be associated with.""" + + model_type: Required[Literal["percent"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + percent_config: Required[PriceEvaluationPriceNewFloatingPercentCompositePricePercentConfig] + """Configuration for percent pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PriceEvaluationPriceNewFloatingPercentCompositePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 PriceEvaluationPriceNewFloatingEventOutputPriceEventOutputConfig(TypedDict, total=False): + """Configuration for event_output pricing""" + + unit_rating_key: Required[str] + """The key in the event data to extract the unit rate from.""" + + default_unit_rate: Optional[str] + """ + If provided, this amount will be used as the unit rate when an event does not + have a value for the `unit_rating_key`. If not provided, events missing a unit + rate will be ignored. + """ + + grouping_key: Optional[str] + """An optional key in the event data to group by (e.g., event ID). + + All events will also be grouped by their unit rate. + """ + + +PriceEvaluationPriceNewFloatingEventOutputPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class PriceEvaluationPriceNewFloatingEventOutputPrice(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.""" + + event_output_config: Required[PriceEvaluationPriceNewFloatingEventOutputPriceEventOutputConfig] + """Configuration for event_output pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["event_output"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[PriceEvaluationPriceNewFloatingEventOutputPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ + + +PriceEvaluationPrice: TypeAlias = Union[ + NewFloatingUnitPrice, + NewFloatingTieredPrice, + NewFloatingBulkPrice, + PriceEvaluationPriceNewFloatingBulkWithFiltersPrice, + NewFloatingPackagePrice, + NewFloatingMatrixPrice, + NewFloatingThresholdTotalAmountPrice, + NewFloatingTieredPackagePrice, + NewFloatingTieredWithMinimumPrice, + NewFloatingGroupedTieredPrice, + NewFloatingTieredPackageWithMinimumPrice, + NewFloatingPackageWithAllocationPrice, + NewFloatingUnitWithPercentPrice, + NewFloatingMatrixWithAllocationPrice, + PriceEvaluationPriceNewFloatingMatrixWithThresholdDiscountsPrice, + NewFloatingTieredWithProrationPrice, + NewFloatingUnitWithProrationPrice, + NewFloatingGroupedAllocationPrice, + NewFloatingBulkWithProrationPrice, + NewFloatingGroupedWithProratedMinimumPrice, + NewFloatingGroupedWithMeteredMinimumPrice, + PriceEvaluationPriceNewFloatingGroupedWithMinMaxThresholdsPrice, + NewFloatingMatrixWithDisplayNamePrice, + NewFloatingGroupedTieredPackagePrice, + NewFloatingMaxGroupTieredPackagePrice, + NewFloatingScalableMatrixWithUnitPricingPrice, + NewFloatingScalableMatrixWithTieredPricingPrice, + NewFloatingCumulativeGroupedBulkPrice, + PriceEvaluationPriceNewFloatingCumulativeGroupedAllocationPrice, + PriceEvaluationPriceNewFloatingDailyCreditAllowancePrice, + PriceEvaluationPriceNewFloatingMeteredAllowancePrice, + NewFloatingMinimumCompositePrice, + PriceEvaluationPriceNewFloatingPercentCompositePrice, + PriceEvaluationPriceNewFloatingEventOutputPrice, +] + + +class PriceEvaluation(TypedDict, total=False): + external_price_id: Optional[str] + """The external ID of a price to evaluate that exists in your Orb account.""" + + filter: Optional[str] + """ + A boolean + [computed property](/extensibility/advanced-metrics#computed-properties) used to + filter the underlying billable metric + """ + + grouping_keys: SequenceNotStr[str] + """ + Properties (or + [computed properties](/extensibility/advanced-metrics#computed-properties)) used + to group the underlying billable metric + """ + + metric_parameter_overrides: Optional[Dict[str, object]] + """Optional overrides for parameterized billable metric parameters. + + If the metric has parameter definitions and no overrides are provided, defaults + will be used. + """ + + price: Optional[PriceEvaluationPrice] + """New floating price request body params.""" + + price_id: Optional[str] + """The ID of a price to evaluate that exists in your Orb account.""" diff --git a/src/orb/types/price_evaluate_preview_events_response.py b/src/orb/types/price_evaluate_preview_events_response.py new file mode 100644 index 00000000..949eeec4 --- /dev/null +++ b/src/orb/types/price_evaluate_preview_events_response.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel +from .evaluate_price_group import EvaluatePriceGroup + +__all__ = ["PriceEvaluatePreviewEventsResponse", "Data"] + + +class Data(BaseModel): + currency: str + """The currency of the price""" + + price_groups: List[EvaluatePriceGroup] + """The computed price groups associated with input price.""" + + external_price_id: Optional[str] = None + """The external ID of the price""" + + inline_price_index: Optional[int] = None + """The index of the inline price""" + + price_id: Optional[str] = None + """The ID of the price""" + + +class PriceEvaluatePreviewEventsResponse(BaseModel): + data: List[Data] diff --git a/src/orb/types/beta/price_evaluate_response.py b/src/orb/types/price_evaluate_response.py similarity index 89% rename from src/orb/types/beta/price_evaluate_response.py rename to src/orb/types/price_evaluate_response.py index debfb4be..793ed493 100644 --- a/src/orb/types/beta/price_evaluate_response.py +++ b/src/orb/types/price_evaluate_response.py @@ -2,7 +2,7 @@ from typing import List -from ..._models import BaseModel +from .._models import BaseModel from .evaluate_price_group import EvaluatePriceGroup __all__ = ["PriceEvaluateResponse"] diff --git a/src/orb/types/price_update_params.py b/src/orb/types/price_update_params.py new file mode 100644 index 00000000..d6396a1b --- /dev/null +++ b/src/orb/types/price_update_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import TypedDict + +__all__ = ["PriceUpdateParams"] + + +class PriceUpdateParams(TypedDict, total=False): + 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`. + """ diff --git a/src/orb/types/prices/__init__.py b/src/orb/types/prices/__init__.py index f8ee8b14..1c214087 100644 --- a/src/orb/types/prices/__init__.py +++ b/src/orb/types/prices/__init__.py @@ -1,3 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from __future__ import annotations + +from .external_price_id_update_params import ExternalPriceIDUpdateParams as ExternalPriceIDUpdateParams diff --git a/src/orb/types/prices/external_price_id_update_params.py b/src/orb/types/prices/external_price_id_update_params.py new file mode 100644 index 00000000..9b431435 --- /dev/null +++ b/src/orb/types/prices/external_price_id_update_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import TypedDict + +__all__ = ["ExternalPriceIDUpdateParams"] + + +class ExternalPriceIDUpdateParams(TypedDict, total=False): + 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`. + """ diff --git a/src/orb/types/shared/__init__.py b/src/orb/types/shared/__init__.py index 59db4f3b..6087ac0f 100644 --- a/src/orb/types/shared/__init__.py +++ b/src/orb/types/shared/__init__.py @@ -1,3 +1,190 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from .tier import Tier as Tier +from .price import Price as Price +from .address import Address as Address +from .invoice import Invoice as Invoice +from .maximum import Maximum as Maximum +from .minimum import Minimum as Minimum from .discount import Discount as Discount +from .bulk_tier import BulkTier as BulkTier +from .item_slim import ItemSlim as ItemSlim +from .allocation import Allocation as Allocation +from .tax_amount import TaxAmount as TaxAmount +from .bulk_config import BulkConfig as BulkConfig +from .credit_note import CreditNote as CreditNote +from .new_maximum import NewMaximum as NewMaximum +from .new_minimum import NewMinimum as NewMinimum +from .unit_config import UnitConfig as UnitConfig +from .invoice_tiny import InvoiceTiny as InvoiceTiny +from .matrix_value import MatrixValue as MatrixValue +from .matrix_config import MatrixConfig as MatrixConfig +from .tiered_config import TieredConfig as TieredConfig +from .package_config import PackageConfig as PackageConfig +from .per_price_cost import PerPriceCost as PerPriceCost +from .price_interval import PriceInterval as PriceInterval +from .trial_discount import TrialDiscount as TrialDiscount +from .usage_discount import UsageDiscount as UsageDiscount +from .aggregated_cost import AggregatedCost as AggregatedCost +from .amount_discount import AmountDiscount as AmountDiscount +from .customer_tax_id import CustomerTaxID as CustomerTaxID +from .credit_note_tiny import CreditNoteTiny as CreditNoteTiny +from .maximum_interval import MaximumInterval as MaximumInterval +from .minimum_interval import MinimumInterval as MinimumInterval +from .coupon_redemption import CouponRedemption as CouponRedemption +from .custom_expiration import CustomExpiration as CustomExpiration +from .customer_minified import CustomerMinified as CustomerMinified +from .new_usage_discount import NewUsageDiscount as NewUsageDiscount +from .tier_sub_line_item import TierSubLineItem as TierSubLineItem +from .adjustment_interval import AdjustmentInterval as AdjustmentInterval +from .new_amount_discount import NewAmountDiscount as NewAmountDiscount +from .new_plan_bulk_price import NewPlanBulkPrice as NewPlanBulkPrice +from .new_plan_unit_price import NewPlanUnitPrice as NewPlanUnitPrice +from .other_sub_line_item import OtherSubLineItem as OtherSubLineItem +from .pagination_metadata import PaginationMetadata as PaginationMetadata +from .percentage_discount import PercentageDiscount as PercentageDiscount +from .billable_metric_tiny import BillableMetricTiny as BillableMetricTiny +from .conversion_rate_tier import ConversionRateTier as ConversionRateTier +from .matrix_sub_line_item import MatrixSubLineItem as MatrixSubLineItem +from .new_allocation_price import NewAllocationPrice as NewAllocationPrice +from .new_plan_matrix_price import NewPlanMatrixPrice as NewPlanMatrixPrice +from .new_plan_tiered_price import NewPlanTieredPrice as NewPlanTieredPrice +from .subscription_minified import SubscriptionMinified as SubscriptionMinified +from .invoice_level_discount import InvoiceLevelDiscount as InvoiceLevelDiscount +from .new_plan_package_price import NewPlanPackagePrice as NewPlanPackagePrice +from .sub_line_item_grouping import SubLineItemGrouping as SubLineItemGrouping +from .new_floating_bulk_price import NewFloatingBulkPrice as NewFloatingBulkPrice +from .new_floating_unit_price import NewFloatingUnitPrice as NewFloatingUnitPrice +from .new_percentage_discount import NewPercentageDiscount as NewPercentageDiscount +from .subscription_trial_info import SubscriptionTrialInfo as SubscriptionTrialInfo +from .usage_discount_interval import UsageDiscountInterval as UsageDiscountInterval +from .amount_discount_interval import AmountDiscountInterval as AmountDiscountInterval +from .new_floating_matrix_price import NewFloatingMatrixPrice as NewFloatingMatrixPrice +from .new_floating_tiered_price import NewFloatingTieredPrice as NewFloatingTieredPrice +from .new_floating_package_price import NewFloatingPackagePrice as NewFloatingPackagePrice +from .billing_cycle_configuration import BillingCycleConfiguration as BillingCycleConfiguration +from .billing_cycle_relative_date import BillingCycleRelativeDate as BillingCycleRelativeDate +from .conversion_rate_unit_config import ConversionRateUnitConfig as ConversionRateUnitConfig +from .monetary_maximum_adjustment import MonetaryMaximumAdjustment as MonetaryMaximumAdjustment +from .monetary_minimum_adjustment import MonetaryMinimumAdjustment as MonetaryMinimumAdjustment +from .sub_line_item_matrix_config import SubLineItemMatrixConfig as SubLineItemMatrixConfig +from .unit_conversion_rate_config import UnitConversionRateConfig as UnitConversionRateConfig +from .percentage_discount_interval import PercentageDiscountInterval as PercentageDiscountInterval +from .subscription_change_minified import SubscriptionChangeMinified as SubscriptionChangeMinified +from .conversion_rate_tiered_config import ConversionRateTieredConfig as ConversionRateTieredConfig +from .fixed_fee_quantity_transition import FixedFeeQuantityTransition as FixedFeeQuantityTransition +from .matrix_with_allocation_config import MatrixWithAllocationConfig as MatrixWithAllocationConfig +from .new_plan_grouped_tiered_price import NewPlanGroupedTieredPrice as NewPlanGroupedTieredPrice +from .new_plan_tiered_package_price import NewPlanTieredPackagePrice as NewPlanTieredPackagePrice +from .plan_phase_maximum_adjustment import PlanPhaseMaximumAdjustment as PlanPhaseMaximumAdjustment +from .plan_phase_minimum_adjustment import PlanPhaseMinimumAdjustment as PlanPhaseMinimumAdjustment +from .tiered_conversion_rate_config import TieredConversionRateConfig as TieredConversionRateConfig +from .changed_subscription_resources import ChangedSubscriptionResources as ChangedSubscriptionResources +from .dimensional_price_configuration import DimensionalPriceConfiguration as DimensionalPriceConfiguration +from .new_billing_cycle_configuration import NewBillingCycleConfiguration as NewBillingCycleConfiguration +from .new_plan_minimum_composite_price import NewPlanMinimumCompositePrice as NewPlanMinimumCompositePrice +from .new_plan_unit_with_percent_price import NewPlanUnitWithPercentPrice as NewPlanUnitWithPercentPrice +from .fixed_fee_quantity_schedule_entry import FixedFeeQuantityScheduleEntry as FixedFeeQuantityScheduleEntry +from .new_floating_grouped_tiered_price import NewFloatingGroupedTieredPrice as NewFloatingGroupedTieredPrice +from .new_floating_tiered_package_price import NewFloatingTieredPackagePrice as NewFloatingTieredPackagePrice +from .new_plan_grouped_allocation_price import NewPlanGroupedAllocationPrice as NewPlanGroupedAllocationPrice +from .billing_cycle_anchor_configuration import BillingCycleAnchorConfiguration as BillingCycleAnchorConfiguration +from .monetary_usage_discount_adjustment import MonetaryUsageDiscountAdjustment as MonetaryUsageDiscountAdjustment +from .new_plan_bulk_with_proration_price import NewPlanBulkWithProrationPrice as NewPlanBulkWithProrationPrice +from .new_plan_tiered_with_minimum_price import NewPlanTieredWithMinimumPrice as NewPlanTieredWithMinimumPrice +from .new_plan_unit_with_proration_price import NewPlanUnitWithProrationPrice as NewPlanUnitWithProrationPrice +from .monetary_amount_discount_adjustment import MonetaryAmountDiscountAdjustment as MonetaryAmountDiscountAdjustment +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration as NewDimensionalPriceConfiguration +from .new_floating_minimum_composite_price import NewFloatingMinimumCompositePrice as NewFloatingMinimumCompositePrice +from .new_floating_unit_with_percent_price import NewFloatingUnitWithPercentPrice as NewFloatingUnitWithPercentPrice +from .plan_phase_usage_discount_adjustment import PlanPhaseUsageDiscountAdjustment as PlanPhaseUsageDiscountAdjustment +from .new_floating_grouped_allocation_price import ( + NewFloatingGroupedAllocationPrice as NewFloatingGroupedAllocationPrice, +) +from .new_plan_grouped_tiered_package_price import NewPlanGroupedTieredPackagePrice as NewPlanGroupedTieredPackagePrice +from .new_plan_matrix_with_allocation_price import NewPlanMatrixWithAllocationPrice as NewPlanMatrixWithAllocationPrice +from .new_plan_threshold_total_amount_price import NewPlanThresholdTotalAmountPrice as NewPlanThresholdTotalAmountPrice +from .plan_phase_amount_discount_adjustment import ( + PlanPhaseAmountDiscountAdjustment as PlanPhaseAmountDiscountAdjustment, +) +from .new_floating_bulk_with_proration_price import ( + NewFloatingBulkWithProrationPrice as NewFloatingBulkWithProrationPrice, +) +from .new_floating_tiered_with_minimum_price import ( + NewFloatingTieredWithMinimumPrice as NewFloatingTieredWithMinimumPrice, +) +from .new_floating_unit_with_proration_price import ( + NewFloatingUnitWithProrationPrice as NewFloatingUnitWithProrationPrice, +) +from .new_plan_cumulative_grouped_bulk_price import ( + NewPlanCumulativeGroupedBulkPrice as NewPlanCumulativeGroupedBulkPrice, +) +from .new_plan_package_with_allocation_price import ( + NewPlanPackageWithAllocationPrice as NewPlanPackageWithAllocationPrice, +) +from .monetary_percentage_discount_adjustment import ( + MonetaryPercentageDiscountAdjustment as MonetaryPercentageDiscountAdjustment, +) +from .new_plan_matrix_with_display_name_price import ( + NewPlanMatrixWithDisplayNamePrice as NewPlanMatrixWithDisplayNamePrice, +) +from .new_plan_max_group_tiered_package_price import ( + NewPlanMaxGroupTieredPackagePrice as NewPlanMaxGroupTieredPackagePrice, +) +from .new_floating_tiered_with_proration_price import ( + NewFloatingTieredWithProrationPrice as NewFloatingTieredWithProrationPrice, +) +from .new_floating_grouped_tiered_package_price import ( + NewFloatingGroupedTieredPackagePrice as NewFloatingGroupedTieredPackagePrice, +) +from .new_floating_matrix_with_allocation_price import ( + NewFloatingMatrixWithAllocationPrice as NewFloatingMatrixWithAllocationPrice, +) +from .new_floating_threshold_total_amount_price import ( + NewFloatingThresholdTotalAmountPrice as NewFloatingThresholdTotalAmountPrice, +) +from .plan_phase_percentage_discount_adjustment import ( + PlanPhasePercentageDiscountAdjustment as PlanPhasePercentageDiscountAdjustment, +) +from .new_floating_cumulative_grouped_bulk_price import ( + NewFloatingCumulativeGroupedBulkPrice as NewFloatingCumulativeGroupedBulkPrice, +) +from .new_floating_package_with_allocation_price import ( + NewFloatingPackageWithAllocationPrice as NewFloatingPackageWithAllocationPrice, +) +from .new_plan_tiered_package_with_minimum_price import ( + NewPlanTieredPackageWithMinimumPrice as NewPlanTieredPackageWithMinimumPrice, +) +from .new_floating_matrix_with_display_name_price import ( + NewFloatingMatrixWithDisplayNamePrice as NewFloatingMatrixWithDisplayNamePrice, +) +from .new_floating_max_group_tiered_package_price import ( + NewFloatingMaxGroupTieredPackagePrice as NewFloatingMaxGroupTieredPackagePrice, +) +from .new_plan_grouped_with_metered_minimum_price import ( + NewPlanGroupedWithMeteredMinimumPrice as NewPlanGroupedWithMeteredMinimumPrice, +) +from .new_plan_grouped_with_prorated_minimum_price import ( + NewPlanGroupedWithProratedMinimumPrice as NewPlanGroupedWithProratedMinimumPrice, +) +from .new_floating_tiered_package_with_minimum_price import ( + NewFloatingTieredPackageWithMinimumPrice as NewFloatingTieredPackageWithMinimumPrice, +) +from .new_floating_grouped_with_metered_minimum_price import ( + NewFloatingGroupedWithMeteredMinimumPrice as NewFloatingGroupedWithMeteredMinimumPrice, +) +from .new_floating_grouped_with_prorated_minimum_price import ( + NewFloatingGroupedWithProratedMinimumPrice as NewFloatingGroupedWithProratedMinimumPrice, +) +from .new_plan_scalable_matrix_with_unit_pricing_price import ( + NewPlanScalableMatrixWithUnitPricingPrice as NewPlanScalableMatrixWithUnitPricingPrice, +) +from .new_plan_scalable_matrix_with_tiered_pricing_price import ( + NewPlanScalableMatrixWithTieredPricingPrice as NewPlanScalableMatrixWithTieredPricingPrice, +) +from .new_floating_scalable_matrix_with_unit_pricing_price import ( + NewFloatingScalableMatrixWithUnitPricingPrice as NewFloatingScalableMatrixWithUnitPricingPrice, +) +from .new_floating_scalable_matrix_with_tiered_pricing_price import ( + NewFloatingScalableMatrixWithTieredPricingPrice as NewFloatingScalableMatrixWithTieredPricingPrice, +) diff --git a/src/orb/types/shared/address.py b/src/orb/types/shared/address.py new file mode 100644 index 00000000..7900b7ea --- /dev/null +++ b/src/orb/types/shared/address.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["Address"] + + +class Address(BaseModel): + city: Optional[str] = None + + country: Optional[str] = None + + line1: Optional[str] = None + + line2: Optional[str] = None + + postal_code: Optional[str] = None + + state: Optional[str] = None diff --git a/src/orb/types/shared/adjustment_interval.py b/src/orb/types/shared/adjustment_interval.py new file mode 100644 index 00000000..588153da --- /dev/null +++ b/src/orb/types/shared/adjustment_interval.py @@ -0,0 +1,122 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .plan_phase_maximum_adjustment import PlanPhaseMaximumAdjustment +from .plan_phase_minimum_adjustment import PlanPhaseMinimumAdjustment +from .plan_phase_usage_discount_adjustment import PlanPhaseUsageDiscountAdjustment +from .plan_phase_amount_discount_adjustment import PlanPhaseAmountDiscountAdjustment +from .plan_phase_percentage_discount_adjustment import PlanPhasePercentageDiscountAdjustment + +__all__ = [ + "AdjustmentInterval", + "Adjustment", + "AdjustmentPlanPhaseTieredPercentageDiscountAdjustment", + "AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentFilter", + "AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentTier", +] + + +class AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentTier(BaseModel): + """One band of a tiered percentage discount. + + Bounds are denominated in the discount's currency. + `lower_bound` is the exclusive start of the band and `upper_bound` is the inclusive end; + `upper_bound` is null only for the open-ended final tier. + """ + + lower_bound: float + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: float + """ + The percentage (between 0 and 1) discounted from spend that falls within this + tier. + """ + + upper_bound: Optional[float] = None + """ + Inclusive upper bound of cumulative spend for this tier; null for the final + open-ended tier. + """ + + +class AdjustmentPlanPhaseTieredPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["tiered_percentage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + filters: List[AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentFilter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, 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.""" + + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. + + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ + + tiers: List[AdjustmentPlanPhaseTieredPercentageDiscountAdjustmentTier] + """ + The ordered, contiguous bands of cumulative eligible spend, each discounted at + its own percentage (progressive fill-a-tier), applied to the prices this + adjustment covers in a given billing period. + """ + + +Adjustment: TypeAlias = Annotated[ + Union[ + PlanPhaseUsageDiscountAdjustment, + PlanPhaseAmountDiscountAdjustment, + PlanPhasePercentageDiscountAdjustment, + AdjustmentPlanPhaseTieredPercentageDiscountAdjustment, + PlanPhaseMinimumAdjustment, + PlanPhaseMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + + +class AdjustmentInterval(BaseModel): + id: str + + adjustment: Adjustment + + 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.""" diff --git a/src/orb/types/shared/aggregated_cost.py b/src/orb/types/shared/aggregated_cost.py new file mode 100644 index 00000000..9236fdf6 --- /dev/null +++ b/src/orb/types/shared/aggregated_cost.py @@ -0,0 +1,23 @@ +# 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 +from .per_price_cost import PerPriceCost + +__all__ = ["AggregatedCost"] + + +class AggregatedCost(BaseModel): + per_price_costs: List[PerPriceCost] + + subtotal: str + """Total costs for the timeframe, excluding any minimums and discounts.""" + + timeframe_end: datetime + + timeframe_start: datetime + + total: str + """Total costs for the timeframe, including any minimums and discounts.""" diff --git a/src/orb/types/shared/allocation.py b/src/orb/types/shared/allocation.py new file mode 100644 index 00000000..69c1cdec --- /dev/null +++ b/src/orb/types/shared/allocation.py @@ -0,0 +1,32 @@ +# 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 +from .custom_expiration import CustomExpiration + +__all__ = ["Allocation", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class Allocation(BaseModel): + allows_rollover: bool + + currency: str + + custom_expiration: Optional[CustomExpiration] = None + + filters: Optional[List[Filter]] = None + + license_type_id: Optional[str] = None diff --git a/src/orb/types/shared/amount_discount.py b/src/orb/types/shared/amount_discount.py new file mode 100644 index 00000000..e2d3506f --- /dev/null +++ b/src/orb/types/shared/amount_discount.py @@ -0,0 +1,37 @@ +# 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", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class AmountDiscount(BaseModel): + amount_discount: str + """Only available if discount_type is `amount`.""" + + discount_type: Literal["amount"] + + applies_to_price_ids: Optional[List[str]] = None + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + filters: Optional[List[Filter]] = None + """The filters that determine which prices to apply this discount to.""" + + reason: Optional[str] = None diff --git a/src/orb/types/shared/amount_discount_interval.py b/src/orb/types/shared/amount_discount_interval.py new file mode 100644 index 00000000..50b35e83 --- /dev/null +++ b/src/orb/types/shared/amount_discount_interval.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["AmountDiscountInterval", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class AmountDiscountInterval(BaseModel): + amount_discount: str + """Only available if discount_type is `amount`.""" + + 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.""" + + filters: List[Filter] + """The filters that determine which prices this discount interval applies to.""" + + start_date: datetime + """The start date of the discount interval.""" diff --git a/src/orb/types/shared/billable_metric_tiny.py b/src/orb/types/shared/billable_metric_tiny.py new file mode 100644 index 00000000..03b21c8b --- /dev/null +++ b/src/orb/types/shared/billable_metric_tiny.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["BillableMetricTiny"] + + +class BillableMetricTiny(BaseModel): + id: str diff --git a/src/orb/types/shared/billing_cycle_anchor_configuration.py b/src/orb/types/shared/billing_cycle_anchor_configuration.py new file mode 100644 index 00000000..386d440c --- /dev/null +++ b/src/orb/types/shared/billing_cycle_anchor_configuration.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["BillingCycleAnchorConfiguration"] + + +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.). + """ diff --git a/src/orb/types/shared/billing_cycle_configuration.py b/src/orb/types/shared/billing_cycle_configuration.py new file mode 100644 index 00000000..d66834f9 --- /dev/null +++ b/src/orb/types/shared/billing_cycle_configuration.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["BillingCycleConfiguration"] + + +class BillingCycleConfiguration(BaseModel): + duration: int + + duration_unit: Literal["day", "month"] diff --git a/src/orb/types/shared/billing_cycle_relative_date.py b/src/orb/types/shared/billing_cycle_relative_date.py new file mode 100644 index 00000000..b4e6a488 --- /dev/null +++ b/src/orb/types/shared/billing_cycle_relative_date.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["BillingCycleRelativeDate"] + +BillingCycleRelativeDate: TypeAlias = Literal["start_of_term", "end_of_term"] diff --git a/src/orb/types/shared/bulk_config.py b/src/orb/types/shared/bulk_config.py new file mode 100644 index 00000000..1bba5545 --- /dev/null +++ b/src/orb/types/shared/bulk_config.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .bulk_tier import BulkTier + +__all__ = ["BulkConfig"] + + +class BulkConfig(BaseModel): + """Configuration for bulk pricing""" + + tiers: List[BulkTier] + """Bulk tiers for rating based on total usage volume""" diff --git a/src/orb/types/shared/bulk_tier.py b/src/orb/types/shared/bulk_tier.py new file mode 100644 index 00000000..bd514c29 --- /dev/null +++ b/src/orb/types/shared/bulk_tier.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["BulkTier"] + + +class BulkTier(BaseModel): + """Configuration for a single bulk pricing tier""" + + unit_amount: str + """Amount per unit""" + + maximum_units: Optional[float] = None + """Upper bound for this tier""" diff --git a/src/orb/types/shared/changed_subscription_resources.py b/src/orb/types/shared/changed_subscription_resources.py new file mode 100644 index 00000000..1bdd1a2c --- /dev/null +++ b/src/orb/types/shared/changed_subscription_resources.py @@ -0,0 +1,674 @@ +# 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 .price import Price +from .address import Address +from .invoice import Invoice +from .maximum import Maximum +from .minimum import Minimum +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .tax_amount import TaxAmount +from .credit_note import CreditNote +from .invoice_tiny import InvoiceTiny +from .customer_tax_id import CustomerTaxID +from .credit_note_tiny import CreditNoteTiny +from .customer_minified import CustomerMinified +from .tier_sub_line_item import TierSubLineItem +from .other_sub_line_item import OtherSubLineItem +from .matrix_sub_line_item import MatrixSubLineItem +from .subscription_minified import SubscriptionMinified +from .invoice_level_discount import InvoiceLevelDiscount +from .monetary_maximum_adjustment import MonetaryMaximumAdjustment +from .monetary_minimum_adjustment import MonetaryMinimumAdjustment +from .monetary_usage_discount_adjustment import MonetaryUsageDiscountAdjustment +from .monetary_amount_discount_adjustment import MonetaryAmountDiscountAdjustment +from .monetary_percentage_discount_adjustment import MonetaryPercentageDiscountAdjustment + +__all__ = [ + "ChangedSubscriptionResources", + "CreatedInvoice", + "CreatedInvoiceAutoCollection", + "CreatedInvoiceCreditNote", + "CreatedInvoiceCustomerBalanceTransaction", + "CreatedInvoiceLineItem", + "CreatedInvoiceLineItemAdjustment", + "CreatedInvoiceLineItemAdjustmentMonetaryTieredPercentageDiscountAdjustment", + "CreatedInvoiceLineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentFilter", + "CreatedInvoiceLineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentTier", + "CreatedInvoiceLineItemSubLineItem", + "CreatedInvoicePaymentAttempt", +] + + +class CreatedInvoiceAutoCollection(BaseModel): + enabled: Optional[bool] = None + """True only if auto-collection is enabled for this invoice.""" + + next_attempt_at: Optional[datetime] = None + """ + If the invoice is scheduled for auto-collection, this field will reflect when + the next attempt will occur. If dunning has been exhausted, or auto-collection + is not enabled for this invoice, this field will be `null`. + """ + + num_attempts: Optional[int] = None + """Number of auto-collection payment attempts.""" + + previously_attempted_at: Optional[datetime] = None + """ + If Orb has ever attempted payment auto-collection for this invoice, this field + will reflect when that attempt occurred. In conjunction with `next_attempt_at`, + this can be used to tell whether the invoice is currently in dunning (that is, + `previously_attempted_at` is non-null, and `next_attempt_time` is non-null), or + if dunning has been exhausted (`previously_attempted_at` is non-null, but + `next_attempt_time` is null). + """ + + +class CreatedInvoiceCreditNote(BaseModel): + id: str + + credit_note_number: str + + memo: Optional[str] = None + """An optional memo supplied on the credit note.""" + + reason: str + + total: str + + type: str + + voided_at: Optional[datetime] = None + """ + If the credit note has a status of `void`, this gives a timestamp when the + credit note was voided. + """ + + +class CreatedInvoiceCustomerBalanceTransaction(BaseModel): + id: str + """A unique id for this transaction.""" + + action: Literal[ + "applied_to_invoice", + "manual_adjustment", + "prorated_refund", + "revert_prorated_refund", + "return_from_voiding", + "credit_note_applied", + "credit_note_voided", + "overpayment_refund", + "external_payment", + "small_invoice_carryover", + ] + + amount: str + """The value of the amount changed in the transaction.""" + + created_at: datetime + """The creation time of this transaction.""" + + credit_note: Optional[CreditNoteTiny] = None + + description: Optional[str] = None + """An optional description provided for manual customer balance adjustments.""" + + ending_balance: str + """ + The new value of the customer's balance prior to the transaction, in the + customer's currency. + """ + + invoice: Optional[InvoiceTiny] = None + + starting_balance: str + """ + The original value of the customer's balance prior to the transaction, in the + customer's currency. + """ + + type: Literal["increment", "decrement"] + + +class CreatedInvoiceLineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class CreatedInvoiceLineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentTier(BaseModel): + """One band of a tiered percentage discount. + + Bounds are denominated in the discount's currency. + `lower_bound` is the exclusive start of the band and `upper_bound` is the inclusive end; + `upper_bound` is null only for the open-ended final tier. + """ + + lower_bound: float + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: float + """ + The percentage (between 0 and 1) discounted from spend that falls within this + tier. + """ + + upper_bound: Optional[float] = None + """ + Inclusive upper bound of cumulative spend for this tier; null for the final + open-ended tier. + """ + + +class CreatedInvoiceLineItemAdjustmentMonetaryTieredPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["tiered_percentage_discount"] + + amount: str + """The value applied by an adjustment.""" + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + filters: List[CreatedInvoiceLineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentFilter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, false for adjustments that + apply to only one price. + """ + + reason: Optional[str] = None + """The reason for the adjustment.""" + + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. + + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ + + tiers: List[CreatedInvoiceLineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentTier] + """ + The ordered, contiguous bands of cumulative eligible spend, each discounted at + its own percentage (progressive fill-a-tier), applied to the prices this + adjustment covers in a given billing period. + """ + + +CreatedInvoiceLineItemAdjustment: TypeAlias = Annotated[ + Union[ + MonetaryUsageDiscountAdjustment, + MonetaryAmountDiscountAdjustment, + MonetaryPercentageDiscountAdjustment, + CreatedInvoiceLineItemAdjustmentMonetaryTieredPercentageDiscountAdjustment, + MonetaryMinimumAdjustment, + MonetaryMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + +CreatedInvoiceLineItemSubLineItem: TypeAlias = Annotated[ + Union[MatrixSubLineItem, TierSubLineItem, OtherSubLineItem], PropertyInfo(discriminator="type") +] + + +class CreatedInvoiceLineItem(BaseModel): + id: str + """A unique ID for this line item.""" + + adjusted_subtotal: str + """ + The line amount after any adjustments and before overage conversion, credits and + partial invoicing. + """ + + adjustments: List[CreatedInvoiceLineItemAdjustment] + """ + All adjustments applied to the line item in the order they were applied based on + invoice calculations (ie. usage discounts -> amount discounts -> percentage + discounts -> minimums -> maximums). + """ + + amount: str + """ + The final amount for a line item after all adjustments and pre paid credits have + been applied. + """ + + credits_applied: str + """The number of prepaid credits applied.""" + + end_date: datetime + """The end date of the range of time applied for this line item's price.""" + + filter: Optional[str] = None + """An additional filter that was used to calculate the usage for this line item.""" + + grouping: Optional[str] = None + """ + [DEPRECATED] For configured prices that are split by a grouping key, this will + be populated with the key and a value. The `amount` and `subtotal` will be the + values for this particular grouping. + """ + + name: str + """The name of the price associated with this line item.""" + + partially_invoiced_amount: str + """Any amount applied from a partial invoice""" + + 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. + + For more on the types of prices, see + [the core concepts documentation](/core-concepts#plan-and-price) + """ + + quantity: float + """Either the fixed fee quantity or the usage during the service period.""" + + start_date: datetime + """The start date of the range of time applied for this line item's price.""" + + sub_line_items: List[CreatedInvoiceLineItemSubLineItem] + """ + For complex pricing structures, the line item can be broken down further in + `sub_line_items`. + """ + + subtotal: str + """The line amount before any adjustments.""" + + tax_amounts: List[TaxAmount] + """An array of tax rates and their incurred tax amounts. + + Empty if no tax integration is configured. + """ + + usage_customer_ids: Optional[List[str]] = None + """ + A list of customer ids that were used to calculate the usage for this line item. + """ + + +class CreatedInvoicePaymentAttempt(BaseModel): + id: str + """The ID of the payment attempt.""" + + amount: str + """The amount of the payment attempt.""" + + created_at: datetime + """The time at which the payment attempt was created.""" + + payment_provider: Optional[Literal["stripe", "adyen"]] = None + """The payment provider that attempted to collect the payment.""" + + payment_provider_id: Optional[str] = None + """The ID of the payment attempt in the payment provider.""" + + receipt_pdf: Optional[str] = None + """URL to the downloadable PDF version of the receipt. + + This field will be `null` for payment attempts that did not succeed. + """ + + succeeded: bool + """Whether the payment attempt succeeded.""" + + +class CreatedInvoice(BaseModel): + id: str + + amount_due: str + """ + This is the final amount required to be charged to the customer and reflects the + application of the customer balance to the `total` of the invoice. + """ + + auto_collection: CreatedInvoiceAutoCollection + + billing_address: Optional[Address] = None + + created_at: datetime + """The creation time of the resource in Orb.""" + + credit_notes: List[CreatedInvoiceCreditNote] + """A list of credit notes associated with the invoice""" + + currency: str + """An ISO 4217 currency string or `credits`""" + + customer: CustomerMinified + + customer_balance_transactions: List[CreatedInvoiceCustomerBalanceTransaction] + + customer_tax_id: Optional[CustomerTaxID] = None + """ + Tax IDs are commonly required to be displayed on customer invoices, which are + added to the headers of invoices. + + ### Supported Tax ID Countries and Types + + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | + """ + + discount: object + """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[InvoiceLevelDiscount] + + due_date: Optional[datetime] = None + """When the invoice payment is due. + + The due date is null if the invoice is not yet finalized. + """ + + eligible_to_issue_at: Optional[datetime] = None + """ + If the invoice has a status of `draft`, this will be the time that the invoice + will be eligible to be issued, otherwise it will be `null`. If `auto-issue` is + true, the invoice will automatically begin issuing at this time. + """ + + hosted_invoice_url: Optional[str] = None + """A URL for the customer-facing invoice portal. + + This URL expires 60 days after the link is generated, or 30 days after the + invoice's due date — whichever is later. + """ + + invoice_date: datetime + """The scheduled date of the invoice""" + + invoice_number: str + """Automatically generated invoice number to help track and reconcile invoices. + + Invoice numbers have a prefix such as `RFOBWG`. These can be sequential per + account or customer. + """ + + invoice_pdf: Optional[str] = None + """The link to download the PDF representation of the `Invoice`.""" + + invoice_source: Literal["subscription", "partial", "one_off"] + + is_payable_now: bool + """True if the invoice has only in-advance fixed fees and is payable now""" + + issue_failed_at: Optional[datetime] = None + """ + If the invoice failed to issue, this will be the last time it failed to issue + (even if it is now in a different state.) + """ + + issued_at: Optional[datetime] = None + """ + If the invoice has been issued, this will be the time it transitioned to + `issued` (even if it is now in a different state.) + """ + + line_items: List[CreatedInvoiceLineItem] + """The breakdown of prices in this invoice.""" + + maximum: Optional[Maximum] = None + + maximum_amount: Optional[str] = None + + memo: Optional[str] = None + """ + Free-form text which is available on the invoice PDF and the Orb invoice portal. + """ + + 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[Minimum] = None + + minimum_amount: Optional[str] = None + + paid_at: Optional[datetime] = None + """ + If the invoice has a status of `paid`, this gives a timestamp when the invoice + was paid. + """ + + payment_attempts: List[CreatedInvoicePaymentAttempt] + """A list of payment attempts associated with the invoice""" + + payment_failed_at: Optional[datetime] = None + """ + If payment was attempted on this invoice but failed, this will be the time of + the most recent attempt. + """ + + payment_started_at: Optional[datetime] = None + """ + If payment was attempted on this invoice, this will be the start time of the + most recent attempt. This field is especially useful for delayed-notification + payment mechanisms (like bank transfers), where payment can take 3 days or more. + """ + + scheduled_issue_at: Optional[datetime] = None + """ + If the invoice is in draft, this timestamp will reflect when the invoice is + scheduled to be issued. + """ + + shipping_address: Optional[Address] = None + + status: Literal["issued", "paid", "synced", "void", "draft"] + + subscription: Optional[SubscriptionMinified] = None + + subtotal: str + """The total before any discounts and minimums are applied.""" + + sync_failed_at: Optional[datetime] = None + """ + If the invoice failed to sync, this will be the last time an external invoicing + provider sync was attempted. This field will always be `null` for invoices using + Orb Invoicing. + """ + + total: str + """The total after any minimums and discounts have been applied.""" + + voided_at: Optional[datetime] = None + """ + If the invoice has a status of `void`, this gives a timestamp when the invoice + was voided. + """ + + will_auto_issue: bool + """ + This is true if the invoice will be automatically issued in the future, and + false otherwise. + """ + + +class ChangedSubscriptionResources(BaseModel): + created_credit_notes: List[CreditNote] + """The credit notes that were created as part of this operation.""" + + created_invoices: List[CreatedInvoice] + """The invoices that were created as part of this operation.""" + + voided_credit_notes: List[CreditNote] + """The credit notes that were voided as part of this operation.""" + + voided_invoices: List[Invoice] + """The invoices that were voided as part of this operation.""" diff --git a/src/orb/types/shared/conversion_rate_tier.py b/src/orb/types/shared/conversion_rate_tier.py new file mode 100644 index 00000000..aba7a449 --- /dev/null +++ b/src/orb/types/shared/conversion_rate_tier.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["ConversionRateTier"] + + +class ConversionRateTier(BaseModel): + first_unit: float + """Exclusive tier starting value""" + + unit_amount: str + """Amount per unit of overage""" + + last_unit: Optional[float] = None + """Inclusive tier ending value. If null, this is treated as the last tier""" diff --git a/src/orb/types/shared/conversion_rate_tiered_config.py b/src/orb/types/shared/conversion_rate_tiered_config.py new file mode 100644 index 00000000..e6d4428d --- /dev/null +++ b/src/orb/types/shared/conversion_rate_tiered_config.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .conversion_rate_tier import ConversionRateTier + +__all__ = ["ConversionRateTieredConfig"] + + +class ConversionRateTieredConfig(BaseModel): + tiers: List[ConversionRateTier] + """Tiers for rating based on total usage quantities into the specified tier""" diff --git a/src/orb/types/shared/conversion_rate_unit_config.py b/src/orb/types/shared/conversion_rate_unit_config.py new file mode 100644 index 00000000..f80c2145 --- /dev/null +++ b/src/orb/types/shared/conversion_rate_unit_config.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["ConversionRateUnitConfig"] + + +class ConversionRateUnitConfig(BaseModel): + unit_amount: str + """Amount per unit of overage""" diff --git a/src/orb/types/shared/coupon_redemption.py b/src/orb/types/shared/coupon_redemption.py new file mode 100644 index 00000000..c9918acf --- /dev/null +++ b/src/orb/types/shared/coupon_redemption.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["CouponRedemption"] + + +class CouponRedemption(BaseModel): + coupon_id: str + + end_date: Optional[datetime] = None + + start_date: datetime diff --git a/src/orb/types/credit_note.py b/src/orb/types/shared/credit_note.py similarity index 79% rename from src/orb/types/credit_note.py rename to src/orb/types/shared/credit_note.py index 465d88b3..b728b6a8 100644 --- a/src/orb/types/credit_note.py +++ b/src/orb/types/shared/credit_note.py @@ -4,45 +4,21 @@ from datetime import datetime from typing_extensions import Literal -from .._models import BaseModel +from ..._models import BaseModel +from .tax_amount import TaxAmount +from .customer_minified import CustomerMinified __all__ = [ "CreditNote", - "Customer", - "Discount", - "DiscountAppliesToPrice", "LineItem", "LineItemDiscount", - "LineItemTaxAmount", "MaximumAmountAdjustment", "MaximumAmountAdjustmentAppliesToPrice", + "Discount", + "DiscountAppliesToPrice", ] -class Customer(BaseModel): - id: str - - external_customer_id: Optional[str] = None - - -class DiscountAppliesToPrice(BaseModel): - id: str - - name: str - - -class Discount(BaseModel): - amount_applied: str - - discount_type: Literal["percentage"] - - percentage_discount: float - - applies_to_prices: Optional[List[DiscountAppliesToPrice]] = None - - reason: Optional[str] = None - - class LineItemDiscount(BaseModel): id: str @@ -59,17 +35,6 @@ class LineItemDiscount(BaseModel): reason: Optional[str] = None -class LineItemTaxAmount(BaseModel): - amount: str - """The amount of additional tax incurred by this tax rate.""" - - tax_rate_description: str - """The human-readable description of the applied tax rate.""" - - tax_rate_percentage: Optional[str] = None - """The tax rate percentage, out of 100.""" - - class LineItem(BaseModel): id: str """The Orb id of this resource.""" @@ -77,8 +42,8 @@ class LineItem(BaseModel): amount: str """The amount of the line item, including any line item minimums and discounts.""" - discounts: List[LineItemDiscount] - """Any line item discounts from the invoice's line item.""" + item_id: str + """The id of the item associated with this line item.""" name: str """The name of the corresponding invoice line item.""" @@ -89,9 +54,18 @@ class LineItem(BaseModel): subtotal: str """The amount of the line item, excluding any line item minimums and discounts.""" - tax_amounts: List[LineItemTaxAmount] + tax_amounts: List[TaxAmount] """Any tax amounts applied onto the line item.""" + discounts: Optional[List[LineItemDiscount]] = None + """Any line item discounts from the invoice's line item.""" + + end_time_exclusive: Optional[datetime] = None + """The end time of the service period for this credit note line item.""" + + start_time_inclusive: Optional[datetime] = None + """The start time of the service period for this credit note line item.""" + class MaximumAmountAdjustmentAppliesToPrice(BaseModel): id: str @@ -100,6 +74,8 @@ class MaximumAmountAdjustmentAppliesToPrice(BaseModel): class MaximumAmountAdjustment(BaseModel): + """The maximum amount applied on the original invoice""" + amount_applied: str discount_type: Literal["percentage"] @@ -111,7 +87,30 @@ class MaximumAmountAdjustment(BaseModel): reason: Optional[str] = None +class DiscountAppliesToPrice(BaseModel): + id: str + + name: str + + +class Discount(BaseModel): + amount_applied: str + + discount_type: Literal["percentage"] + + percentage_discount: float + + applies_to_prices: Optional[List[DiscountAppliesToPrice]] = None + + reason: Optional[str] = None + + class CreditNote(BaseModel): + """ + The [Credit Note](/invoicing/credit-notes) resource represents a credit that has been applied to a + particular invoice. + """ + id: str """The Orb id of this credit note.""" @@ -124,10 +123,7 @@ class CreditNote(BaseModel): credit_note_pdf: Optional[str] = None """A URL to a PDF of the credit note.""" - customer: Customer - - discounts: List[Discount] - """Any discounts applied on the original invoice.""" + customer: CustomerMinified invoice_id: str """The id of the invoice resource that this credit note is applied to.""" @@ -156,3 +152,6 @@ class CreditNote(BaseModel): voided_at: Optional[datetime] = None """The time at which the credit note was voided in Orb, if applicable.""" + + discounts: Optional[List[Discount]] = None + """Any discounts applied on the original invoice.""" diff --git a/src/orb/types/shared/credit_note_tiny.py b/src/orb/types/shared/credit_note_tiny.py new file mode 100644 index 00000000..325c804b --- /dev/null +++ b/src/orb/types/shared/credit_note_tiny.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["CreditNoteTiny"] + + +class CreditNoteTiny(BaseModel): + id: str + """The id of the Credit note""" diff --git a/src/orb/types/shared/custom_expiration.py b/src/orb/types/shared/custom_expiration.py new file mode 100644 index 00000000..76570dc2 --- /dev/null +++ b/src/orb/types/shared/custom_expiration.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["CustomExpiration"] + + +class CustomExpiration(BaseModel): + duration: int + + duration_unit: Literal["day", "month"] diff --git a/src/orb/types/shared/customer_minified.py b/src/orb/types/shared/customer_minified.py new file mode 100644 index 00000000..7eab1e91 --- /dev/null +++ b/src/orb/types/shared/customer_minified.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["CustomerMinified"] + + +class CustomerMinified(BaseModel): + id: str + + external_customer_id: Optional[str] = None diff --git a/src/orb/types/shared/customer_tax_id.py b/src/orb/types/shared/customer_tax_id.py new file mode 100644 index 00000000..adae4925 --- /dev/null +++ b/src/orb/types/shared/customer_tax_id.py @@ -0,0 +1,403 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["CustomerTaxID"] + + +class CustomerTaxID(BaseModel): + """ + Tax IDs are commonly required to be displayed on customer invoices, which are added to the headers of invoices. + + + ### Supported Tax ID Countries and Types + + + | Country | Type | Description | + |---------|------|-------------| + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | + | Japan | `jp_trn` | Japanese Tax Registration Number (*Tōroku Bangō*) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | + """ + + country: Literal[ + "AD", + "AE", + "AL", + "AM", + "AO", + "AR", + "AT", + "AU", + "AW", + "AZ", + "BA", + "BB", + "BD", + "BE", + "BF", + "BG", + "BH", + "BJ", + "BO", + "BR", + "BS", + "BY", + "CA", + "CD", + "CH", + "CL", + "CM", + "CN", + "CO", + "CR", + "CV", + "CY", + "CZ", + "DE", + "DK", + "DO", + "EC", + "EE", + "EG", + "ES", + "ET", + "EU", + "FI", + "FO", + "FR", + "GB", + "GE", + "GI", + "GN", + "GR", + "HK", + "HR", + "HU", + "ID", + "IE", + "IL", + "IN", + "IS", + "IT", + "JP", + "KE", + "KG", + "KH", + "KR", + "KZ", + "LA", + "LI", + "LK", + "LT", + "LU", + "LV", + "MA", + "MD", + "ME", + "MK", + "MR", + "MT", + "MX", + "MY", + "NG", + "NL", + "NO", + "NP", + "NZ", + "OM", + "PE", + "PH", + "PL", + "PT", + "PY", + "RO", + "RS", + "RU", + "SA", + "SE", + "SG", + "SI", + "SK", + "SN", + "SR", + "SV", + "TH", + "TJ", + "TR", + "TW", + "TZ", + "UA", + "UG", + "US", + "UY", + "UZ", + "VE", + "VN", + "ZA", + "ZM", + "ZW", + ] + + type: Literal[ + "ad_nrt", + "ae_trn", + "al_tin", + "am_tin", + "ao_tin", + "ar_cuit", + "eu_vat", + "au_abn", + "au_arn", + "aw_tin", + "az_tin", + "ba_tin", + "bb_tin", + "bd_bin", + "bf_ifu", + "bg_uic", + "bh_vat", + "bj_ifu", + "bo_tin", + "br_cnpj", + "br_cpf", + "bs_tin", + "by_tin", + "ca_bn", + "ca_gst_hst", + "ca_pst_bc", + "ca_pst_mb", + "ca_pst_sk", + "ca_qst", + "cd_nif", + "ch_uid", + "ch_vat", + "cl_tin", + "cm_niu", + "cn_tin", + "co_nit", + "cr_tin", + "cv_nif", + "de_stn", + "do_rcn", + "ec_ruc", + "eg_tin", + "es_cif", + "et_tin", + "eu_oss_vat", + "fo_vat", + "gb_vat", + "ge_vat", + "gi_tin", + "gn_nif", + "hk_br", + "hr_oib", + "hu_tin", + "id_npwp", + "il_vat", + "in_gst", + "is_vat", + "it_cf", + "jp_cn", + "jp_rn", + "jp_trn", + "ke_pin", + "kg_tin", + "kh_tin", + "kr_brn", + "kz_bin", + "la_tin", + "li_uid", + "li_vat", + "lk_vat", + "ma_vat", + "md_vat", + "me_pib", + "mk_vat", + "mr_nif", + "mx_rfc", + "my_frp", + "my_itn", + "my_sst", + "ng_tin", + "no_vat", + "no_voec", + "np_pan", + "nz_gst", + "om_vat", + "pe_ruc", + "ph_tin", + "pl_nip", + "py_ruc", + "ro_tin", + "rs_pib", + "ru_inn", + "ru_kpp", + "sa_vat", + "sg_gst", + "sg_uen", + "si_tin", + "sn_ninea", + "sr_fin", + "sv_nit", + "th_vat", + "tj_tin", + "tr_tin", + "tw_vat", + "tz_vat", + "ua_vat", + "ug_tin", + "us_ein", + "uy_ruc", + "uz_tin", + "uz_vat", + "ve_rif", + "vn_tin", + "za_vat", + "zm_tin", + "zw_tin", + ] + + value: str diff --git a/src/orb/types/shared/dimensional_price_configuration.py b/src/orb/types/shared/dimensional_price_configuration.py new file mode 100644 index 00000000..eed85d21 --- /dev/null +++ b/src/orb/types/shared/dimensional_price_configuration.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel + +__all__ = ["DimensionalPriceConfiguration"] + + +class DimensionalPriceConfiguration(BaseModel): + dimension_values: List[str] + + dimensional_price_group_id: str diff --git a/src/orb/types/shared/discount.py b/src/orb/types/shared/discount.py index 1e0b9172..db3cc47a 100644 --- a/src/orb/types/shared/discount.py +++ b/src/orb/types/shared/discount.py @@ -1,80 +1,76 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import List, Union, Optional -from typing_extensions import Literal +from typing_extensions import Literal, Annotated, TypeAlias +from ..._utils import PropertyInfo from ..._models import BaseModel +from .trial_discount import TrialDiscount +from .usage_discount import UsageDiscount +from .amount_discount import AmountDiscount +from .percentage_discount import PercentageDiscount -__all__ = ["Discount", "PercentageDiscount", "TrialDiscount", "UsageDiscount", "AmountDiscount"] +__all__ = ["Discount", "TieredPercentageDiscount", "TieredPercentageDiscountTier", "TieredPercentageDiscountFilter"] -class PercentageDiscount(BaseModel): - applies_to_price_ids: List[str] - """List of price_ids that this discount applies to. +class TieredPercentageDiscountTier(BaseModel): + """One band of a tiered percentage discount. - For plan/plan phase discounts, this can be a subset of prices. + Bounds are denominated in the discount's currency. + `lower_bound` is the exclusive start of the band and `upper_bound` is the inclusive end; + `upper_bound` is null only for the open-ended final tier. """ - discount_type: Literal["percentage"] - - percentage_discount: float - """Only available if discount_type is `percentage`. + lower_bound: float + """Exclusive lower bound of cumulative spend for this tier.""" - This is a number between 0 and 1. + percentage: float """ - - 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. + The percentage (between 0 and 1) discounted from spend that falls within this + tier. """ - discount_type: Literal["trial"] - - reason: Optional[str] = None + upper_bound: Optional[float] = None + """ + Inclusive upper bound of cumulative spend for this tier; null for the final + open-ended tier. + """ - 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`""" +class TieredPercentageDiscountFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" -class UsageDiscount(BaseModel): - applies_to_price_ids: List[str] - """List of price_ids that this discount applies to. + values: List[str] + """The IDs or values that match this filter.""" - For plan/plan phase discounts, this can be a subset of prices. - """ - discount_type: Literal["usage"] +class TieredPercentageDiscount(BaseModel): + discount_type: Literal["tiered_percentage"] - usage_discount: float - """Only available if discount_type is `usage`. + tiers: List[TieredPercentageDiscountTier] + """Only available if discount_type is `tiered_percentage`. - Number of usage units that this discount is for + The ordered, contiguous bands of cumulative eligible spend, each discounted at + its own percentage (progressive fill-a-tier). """ - reason: Optional[str] = None - - -class AmountDiscount(BaseModel): - amount_discount: str - """Only available if discount_type is `amount`.""" - - applies_to_price_ids: List[str] + applies_to_price_ids: Optional[List[str]] = None """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"] + filters: Optional[List[TieredPercentageDiscountFilter]] = None + """The filters that determine which prices to apply this discount to.""" reason: Optional[str] = None -Discount = Union[PercentageDiscount, TrialDiscount, UsageDiscount, AmountDiscount] +Discount: TypeAlias = Annotated[ + Union[PercentageDiscount, TrialDiscount, UsageDiscount, AmountDiscount, TieredPercentageDiscount], + PropertyInfo(discriminator="discount_type"), +] diff --git a/src/orb/types/shared/fixed_fee_quantity_schedule_entry.py b/src/orb/types/shared/fixed_fee_quantity_schedule_entry.py new file mode 100644 index 00000000..de32eded --- /dev/null +++ b/src/orb/types/shared/fixed_fee_quantity_schedule_entry.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["FixedFeeQuantityScheduleEntry"] + + +class FixedFeeQuantityScheduleEntry(BaseModel): + end_date: Optional[datetime] = None + + price_id: str + + quantity: float + + start_date: datetime diff --git a/src/orb/types/shared/fixed_fee_quantity_transition.py b/src/orb/types/shared/fixed_fee_quantity_transition.py new file mode 100644 index 00000000..60c0ac5a --- /dev/null +++ b/src/orb/types/shared/fixed_fee_quantity_transition.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["FixedFeeQuantityTransition"] + + +class FixedFeeQuantityTransition(BaseModel): + effective_date: datetime + + price_id: str + + quantity: int diff --git a/src/orb/types/shared/invoice.py b/src/orb/types/shared/invoice.py new file mode 100644 index 00000000..9b583cc8 --- /dev/null +++ b/src/orb/types/shared/invoice.py @@ -0,0 +1,661 @@ +# 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 .price import Price +from .address import Address +from .maximum import Maximum +from .minimum import Minimum +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .tax_amount import TaxAmount +from .invoice_tiny import InvoiceTiny +from .customer_tax_id import CustomerTaxID +from .credit_note_tiny import CreditNoteTiny +from .customer_minified import CustomerMinified +from .tier_sub_line_item import TierSubLineItem +from .other_sub_line_item import OtherSubLineItem +from .matrix_sub_line_item import MatrixSubLineItem +from .subscription_minified import SubscriptionMinified +from .invoice_level_discount import InvoiceLevelDiscount +from .monetary_maximum_adjustment import MonetaryMaximumAdjustment +from .monetary_minimum_adjustment import MonetaryMinimumAdjustment +from .monetary_usage_discount_adjustment import MonetaryUsageDiscountAdjustment +from .monetary_amount_discount_adjustment import MonetaryAmountDiscountAdjustment +from .monetary_percentage_discount_adjustment import MonetaryPercentageDiscountAdjustment + +__all__ = [ + "Invoice", + "AutoCollection", + "CreditNote", + "CustomerBalanceTransaction", + "LineItem", + "LineItemAdjustment", + "LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustment", + "LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentFilter", + "LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentTier", + "LineItemSubLineItem", + "PaymentAttempt", +] + + +class AutoCollection(BaseModel): + enabled: Optional[bool] = None + """True only if auto-collection is enabled for this invoice.""" + + next_attempt_at: Optional[datetime] = None + """ + If the invoice is scheduled for auto-collection, this field will reflect when + the next attempt will occur. If dunning has been exhausted, or auto-collection + is not enabled for this invoice, this field will be `null`. + """ + + num_attempts: Optional[int] = None + """Number of auto-collection payment attempts.""" + + previously_attempted_at: Optional[datetime] = None + """ + If Orb has ever attempted payment auto-collection for this invoice, this field + will reflect when that attempt occurred. In conjunction with `next_attempt_at`, + this can be used to tell whether the invoice is currently in dunning (that is, + `previously_attempted_at` is non-null, and `next_attempt_time` is non-null), or + if dunning has been exhausted (`previously_attempted_at` is non-null, but + `next_attempt_time` is null). + """ + + +class CreditNote(BaseModel): + id: str + + credit_note_number: str + + memo: Optional[str] = None + """An optional memo supplied on the credit note.""" + + reason: str + + total: str + + type: str + + voided_at: Optional[datetime] = None + """ + If the credit note has a status of `void`, this gives a timestamp when the + credit note was voided. + """ + + +class CustomerBalanceTransaction(BaseModel): + id: str + """A unique id for this transaction.""" + + action: Literal[ + "applied_to_invoice", + "manual_adjustment", + "prorated_refund", + "revert_prorated_refund", + "return_from_voiding", + "credit_note_applied", + "credit_note_voided", + "overpayment_refund", + "external_payment", + "small_invoice_carryover", + ] + + amount: str + """The value of the amount changed in the transaction.""" + + created_at: datetime + """The creation time of this transaction.""" + + credit_note: Optional[CreditNoteTiny] = None + + description: Optional[str] = None + """An optional description provided for manual customer balance adjustments.""" + + ending_balance: str + """ + The new value of the customer's balance prior to the transaction, in the + customer's currency. + """ + + invoice: Optional[InvoiceTiny] = None + + starting_balance: str + """ + The original value of the customer's balance prior to the transaction, in the + customer's currency. + """ + + type: Literal["increment", "decrement"] + + +class LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentTier(BaseModel): + """One band of a tiered percentage discount. + + Bounds are denominated in the discount's currency. + `lower_bound` is the exclusive start of the band and `upper_bound` is the inclusive end; + `upper_bound` is null only for the open-ended final tier. + """ + + lower_bound: float + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: float + """ + The percentage (between 0 and 1) discounted from spend that falls within this + tier. + """ + + upper_bound: Optional[float] = None + """ + Inclusive upper bound of cumulative spend for this tier; null for the final + open-ended tier. + """ + + +class LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["tiered_percentage_discount"] + + amount: str + """The value applied by an adjustment.""" + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + filters: List[LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentFilter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, false for adjustments that + apply to only one price. + """ + + reason: Optional[str] = None + """The reason for the adjustment.""" + + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. + + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ + + tiers: List[LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustmentTier] + """ + The ordered, contiguous bands of cumulative eligible spend, each discounted at + its own percentage (progressive fill-a-tier), applied to the prices this + adjustment covers in a given billing period. + """ + + +LineItemAdjustment: TypeAlias = Annotated[ + Union[ + MonetaryUsageDiscountAdjustment, + MonetaryAmountDiscountAdjustment, + MonetaryPercentageDiscountAdjustment, + LineItemAdjustmentMonetaryTieredPercentageDiscountAdjustment, + MonetaryMinimumAdjustment, + MonetaryMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + +LineItemSubLineItem: TypeAlias = Annotated[ + Union[MatrixSubLineItem, TierSubLineItem, OtherSubLineItem], PropertyInfo(discriminator="type") +] + + +class LineItem(BaseModel): + id: str + """A unique ID for this line item.""" + + adjusted_subtotal: str + """ + The line amount after any adjustments and before overage conversion, credits and + partial invoicing. + """ + + adjustments: List[LineItemAdjustment] + """ + All adjustments applied to the line item in the order they were applied based on + invoice calculations (ie. usage discounts -> amount discounts -> percentage + discounts -> minimums -> maximums). + """ + + amount: str + """ + The final amount for a line item after all adjustments and pre paid credits have + been applied. + """ + + credits_applied: str + """The number of prepaid credits applied.""" + + end_date: datetime + """The end date of the range of time applied for this line item's price.""" + + filter: Optional[str] = None + """An additional filter that was used to calculate the usage for this line item.""" + + grouping: Optional[str] = None + """ + [DEPRECATED] For configured prices that are split by a grouping key, this will + be populated with the key and a value. The `amount` and `subtotal` will be the + values for this particular grouping. + """ + + name: str + """The name of the price associated with this line item.""" + + partially_invoiced_amount: str + """Any amount applied from a partial invoice""" + + 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. + + For more on the types of prices, see + [the core concepts documentation](/core-concepts#plan-and-price) + """ + + quantity: float + """Either the fixed fee quantity or the usage during the service period.""" + + start_date: datetime + """The start date of the range of time applied for this line item's price.""" + + sub_line_items: List[LineItemSubLineItem] + """ + For complex pricing structures, the line item can be broken down further in + `sub_line_items`. + """ + + subtotal: str + """The line amount before any adjustments.""" + + tax_amounts: List[TaxAmount] + """An array of tax rates and their incurred tax amounts. + + Empty if no tax integration is configured. + """ + + usage_customer_ids: Optional[List[str]] = None + """ + A list of customer ids that were used to calculate the usage for this line item. + """ + + +class PaymentAttempt(BaseModel): + id: str + """The ID of the payment attempt.""" + + amount: str + """The amount of the payment attempt.""" + + created_at: datetime + """The time at which the payment attempt was created.""" + + payment_provider: Optional[Literal["stripe", "adyen"]] = None + """The payment provider that attempted to collect the payment.""" + + payment_provider_id: Optional[str] = None + """The ID of the payment attempt in the payment provider.""" + + receipt_pdf: Optional[str] = None + """URL to the downloadable PDF version of the receipt. + + This field will be `null` for payment attempts that did not succeed. + """ + + succeeded: bool + """Whether the payment attempt succeeded.""" + + +class Invoice(BaseModel): + """ + An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing the request for payment for + a single subscription. This includes a set of line items, which correspond to prices in the subscription's plan and + can represent fixed recurring fees or usage-based fees. They are generated at the end of a billing period, or as + the result of an action, such as a cancellation. + """ + + id: str + + amount_due: str + """ + This is the final amount required to be charged to the customer and reflects the + application of the customer balance to the `total` of the invoice. + """ + + auto_collection: AutoCollection + + billing_address: Optional[Address] = None + + created_at: datetime + """The creation time of the resource in Orb.""" + + credit_notes: List[CreditNote] + """A list of credit notes associated with the invoice""" + + currency: str + """An ISO 4217 currency string or `credits`""" + + customer: CustomerMinified + + customer_balance_transactions: List[CustomerBalanceTransaction] + + customer_tax_id: Optional[CustomerTaxID] = None + """ + Tax IDs are commonly required to be displayed on customer invoices, which are + added to the headers of invoices. + + ### Supported Tax ID Countries and Types + + | Country | Type | Description | + | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) | + | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | + """ + + discount: object + """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[InvoiceLevelDiscount] + + due_date: Optional[datetime] = None + """When the invoice payment is due. + + The due date is null if the invoice is not yet finalized. + """ + + eligible_to_issue_at: Optional[datetime] = None + """ + If the invoice has a status of `draft`, this will be the time that the invoice + will be eligible to be issued, otherwise it will be `null`. If `auto-issue` is + true, the invoice will automatically begin issuing at this time. + """ + + hosted_invoice_url: Optional[str] = None + """A URL for the customer-facing invoice portal. + + This URL expires 60 days after the link is generated, or 30 days after the + invoice's due date — whichever is later. + """ + + invoice_date: datetime + """The scheduled date of the invoice""" + + invoice_number: str + """Automatically generated invoice number to help track and reconcile invoices. + + Invoice numbers have a prefix such as `RFOBWG`. These can be sequential per + account or customer. + """ + + invoice_pdf: Optional[str] = None + """The link to download the PDF representation of the `Invoice`.""" + + invoice_source: Literal["subscription", "partial", "one_off"] + + issue_failed_at: Optional[datetime] = None + """ + If the invoice failed to issue, this will be the last time it failed to issue + (even if it is now in a different state.) + """ + + issued_at: Optional[datetime] = None + """ + If the invoice has been issued, this will be the time it transitioned to + `issued` (even if it is now in a different state.) + """ + + line_items: List[LineItem] + """The breakdown of prices in this invoice.""" + + maximum: Optional[Maximum] = None + + maximum_amount: Optional[str] = None + + memo: Optional[str] = None + """ + Free-form text which is available on the invoice PDF and the Orb invoice portal. + """ + + 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[Minimum] = None + + minimum_amount: Optional[str] = None + + paid_at: Optional[datetime] = None + """ + If the invoice has a status of `paid`, this gives a timestamp when the invoice + was paid. + """ + + payment_attempts: List[PaymentAttempt] + """A list of payment attempts associated with the invoice""" + + payment_failed_at: Optional[datetime] = None + """ + If payment was attempted on this invoice but failed, this will be the time of + the most recent attempt. + """ + + payment_started_at: Optional[datetime] = None + """ + If payment was attempted on this invoice, this will be the start time of the + most recent attempt. This field is especially useful for delayed-notification + payment mechanisms (like bank transfers), where payment can take 3 days or more. + """ + + scheduled_issue_at: Optional[datetime] = None + """ + If the invoice is in draft, this timestamp will reflect when the invoice is + scheduled to be issued. + """ + + shipping_address: Optional[Address] = None + + status: Literal["issued", "paid", "synced", "void", "draft"] + + subscription: Optional[SubscriptionMinified] = None + + subtotal: str + """The total before any discounts and minimums are applied.""" + + sync_failed_at: Optional[datetime] = None + """ + If the invoice failed to sync, this will be the last time an external invoicing + provider sync was attempted. This field will always be `null` for invoices using + Orb Invoicing. + """ + + total: str + """The total after any minimums and discounts have been applied.""" + + voided_at: Optional[datetime] = None + """ + If the invoice has a status of `void`, this gives a timestamp when the invoice + was voided. + """ + + will_auto_issue: bool + """ + This is true if the invoice will be automatically issued in the future, and + false otherwise. + """ 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..81b67f3c --- /dev/null +++ b/src/orb/types/shared/invoice_level_discount.py @@ -0,0 +1,80 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .trial_discount import TrialDiscount +from .amount_discount import AmountDiscount +from .percentage_discount import PercentageDiscount + +__all__ = [ + "InvoiceLevelDiscount", + "TieredPercentageDiscount", + "TieredPercentageDiscountTier", + "TieredPercentageDiscountFilter", +] + + +class TieredPercentageDiscountTier(BaseModel): + """One band of a tiered percentage discount. + + Bounds are denominated in the discount's currency. + `lower_bound` is the exclusive start of the band and `upper_bound` is the inclusive end; + `upper_bound` is null only for the open-ended final tier. + """ + + lower_bound: float + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: float + """ + The percentage (between 0 and 1) discounted from spend that falls within this + tier. + """ + + upper_bound: Optional[float] = None + """ + Inclusive upper bound of cumulative spend for this tier; null for the final + open-ended tier. + """ + + +class TieredPercentageDiscountFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class TieredPercentageDiscount(BaseModel): + discount_type: Literal["tiered_percentage"] + + tiers: List[TieredPercentageDiscountTier] + """Only available if discount_type is `tiered_percentage`. + + The ordered, contiguous bands of cumulative eligible spend, each discounted at + its own percentage (progressive fill-a-tier). + """ + + applies_to_price_ids: Optional[List[str]] = None + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + filters: Optional[List[TieredPercentageDiscountFilter]] = None + """The filters that determine which prices to apply this discount to.""" + + reason: Optional[str] = None + + +InvoiceLevelDiscount: TypeAlias = Annotated[ + Union[PercentageDiscount, AmountDiscount, TrialDiscount, TieredPercentageDiscount], + PropertyInfo(discriminator="discount_type"), +] diff --git a/src/orb/types/shared/invoice_tiny.py b/src/orb/types/shared/invoice_tiny.py new file mode 100644 index 00000000..eb0f7743 --- /dev/null +++ b/src/orb/types/shared/invoice_tiny.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["InvoiceTiny"] + + +class InvoiceTiny(BaseModel): + id: str + """The Invoice id""" diff --git a/src/orb/types/shared/item_slim.py b/src/orb/types/shared/item_slim.py new file mode 100644 index 00000000..7d8cce68 --- /dev/null +++ b/src/orb/types/shared/item_slim.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["ItemSlim"] + + +class ItemSlim(BaseModel): + """ + A minimal representation of an Item containing only the essential identifying information. + """ + + id: str + """The Orb-assigned unique identifier for the item.""" + + name: str + """The name of the item.""" diff --git a/src/orb/types/shared/matrix_config.py b/src/orb/types/shared/matrix_config.py new file mode 100644 index 00000000..4cafc220 --- /dev/null +++ b/src/orb/types/shared/matrix_config.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .matrix_value import MatrixValue + +__all__ = ["MatrixConfig"] + + +class MatrixConfig(BaseModel): + """Configuration for matrix pricing""" + + default_unit_amount: str + """Default per unit rate for any usage not bucketed into a specified matrix_value""" + + dimensions: List[Optional[str]] + """One or two event property values to evaluate matrix groups by""" + + matrix_values: List[MatrixValue] + """Matrix values configuration""" diff --git a/src/orb/types/shared/matrix_sub_line_item.py b/src/orb/types/shared/matrix_sub_line_item.py new file mode 100644 index 00000000..3658b878 --- /dev/null +++ b/src/orb/types/shared/matrix_sub_line_item.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .sub_line_item_grouping import SubLineItemGrouping +from .sub_line_item_matrix_config import SubLineItemMatrixConfig + +__all__ = ["MatrixSubLineItem"] + + +class MatrixSubLineItem(BaseModel): + amount: str + """The total amount for this sub line item.""" + + grouping: Optional[SubLineItemGrouping] = None + + matrix_config: SubLineItemMatrixConfig + + name: str + + quantity: float + + type: Literal["matrix"] + + scaled_quantity: Optional[float] = None + """The scaled quantity for this line item for specific pricing structures""" diff --git a/src/orb/types/shared/matrix_value.py b/src/orb/types/shared/matrix_value.py new file mode 100644 index 00000000..c905043f --- /dev/null +++ b/src/orb/types/shared/matrix_value.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["MatrixValue"] + + +class MatrixValue(BaseModel): + """Configuration for a single matrix value""" + + dimension_values: List[Optional[str]] + """One or two matrix keys to filter usage to this Matrix value by""" + + unit_amount: str + """Unit price for the specified dimension_values""" diff --git a/src/orb/types/shared/matrix_with_allocation_config.py b/src/orb/types/shared/matrix_with_allocation_config.py new file mode 100644 index 00000000..e632f982 --- /dev/null +++ b/src/orb/types/shared/matrix_with_allocation_config.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["MatrixWithAllocationConfig", "MatrixValue"] + + +class MatrixValue(BaseModel): + """Configuration for a single matrix value""" + + dimension_values: 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: str + """Unit price for the specified dimension_values""" + + +class MatrixWithAllocationConfig(BaseModel): + """Configuration for matrix pricing with usage allocation""" + + allocation: str + """Usage allocation""" + + default_unit_amount: str + """Default per unit rate for any usage not bucketed into a specified matrix_value""" + + dimensions: List[Optional[str]] + """One or two event property values to evaluate matrix groups by""" + + matrix_values: List[MatrixValue] + """Matrix values configuration""" diff --git a/src/orb/types/shared/maximum.py b/src/orb/types/shared/maximum.py new file mode 100644 index 00000000..c4d6d314 --- /dev/null +++ b/src/orb/types/shared/maximum.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["Maximum", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class Maximum(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. + """ + + filters: List[Filter] + """The filters that determine which prices to apply this maximum to.""" + + maximum_amount: str + """Maximum amount applied""" diff --git a/src/orb/types/shared/maximum_interval.py b/src/orb/types/shared/maximum_interval.py new file mode 100644 index 00000000..34f903d0 --- /dev/null +++ b/src/orb/types/shared/maximum_interval.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["MaximumInterval", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class MaximumInterval(BaseModel): + 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.""" + + filters: List[Filter] + """The filters that determine which prices this maximum interval applies to.""" + + 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.""" diff --git a/src/orb/types/shared/minimum.py b/src/orb/types/shared/minimum.py new file mode 100644 index 00000000..c5d7a162 --- /dev/null +++ b/src/orb/types/shared/minimum.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["Minimum", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class Minimum(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. + """ + + filters: List[Filter] + """The filters that determine which prices to apply this minimum to.""" + + minimum_amount: str + """Minimum amount applied""" diff --git a/src/orb/types/shared/minimum_interval.py b/src/orb/types/shared/minimum_interval.py new file mode 100644 index 00000000..94e8bddc --- /dev/null +++ b/src/orb/types/shared/minimum_interval.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["MinimumInterval", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class MinimumInterval(BaseModel): + 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.""" + + filters: List[Filter] + """The filters that determine which prices this minimum interval applies to.""" + + 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.""" diff --git a/src/orb/types/shared/monetary_amount_discount_adjustment.py b/src/orb/types/shared/monetary_amount_discount_adjustment.py new file mode 100644 index 00000000..1896ce77 --- /dev/null +++ b/src/orb/types/shared/monetary_amount_discount_adjustment.py @@ -0,0 +1,56 @@ +# 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__ = ["MonetaryAmountDiscountAdjustment", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class MonetaryAmountDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["amount_discount"] + + amount: str + """The value applied by an adjustment.""" + + 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.""" + + filters: List[Filter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, false for adjustments that + apply to only one price. + """ + + reason: Optional[str] = None + """The reason for the adjustment.""" + + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. + + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ diff --git a/src/orb/types/shared/monetary_maximum_adjustment.py b/src/orb/types/shared/monetary_maximum_adjustment.py new file mode 100644 index 00000000..9a814dde --- /dev/null +++ b/src/orb/types/shared/monetary_maximum_adjustment.py @@ -0,0 +1,56 @@ +# 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__ = ["MonetaryMaximumAdjustment", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class MonetaryMaximumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["maximum"] + + amount: str + """The value applied by an adjustment.""" + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + filters: List[Filter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, 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. + """ + + reason: Optional[str] = None + """The reason for the adjustment.""" + + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. + + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ diff --git a/src/orb/types/shared/monetary_minimum_adjustment.py b/src/orb/types/shared/monetary_minimum_adjustment.py new file mode 100644 index 00000000..f7b3939f --- /dev/null +++ b/src/orb/types/shared/monetary_minimum_adjustment.py @@ -0,0 +1,59 @@ +# 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__ = ["MonetaryMinimumAdjustment", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class MonetaryMinimumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["minimum"] + + amount: str + """The value applied by an adjustment.""" + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + filters: List[Filter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, 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. + """ + + reason: Optional[str] = None + """The reason for the adjustment.""" + + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. + + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ diff --git a/src/orb/types/shared/monetary_percentage_discount_adjustment.py b/src/orb/types/shared/monetary_percentage_discount_adjustment.py new file mode 100644 index 00000000..be0cd7fe --- /dev/null +++ b/src/orb/types/shared/monetary_percentage_discount_adjustment.py @@ -0,0 +1,56 @@ +# 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__ = ["MonetaryPercentageDiscountAdjustment", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class MonetaryPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["percentage_discount"] + + amount: str + """The value applied by an adjustment.""" + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + filters: List[Filter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, 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. + """ + + reason: Optional[str] = None + """The reason for the adjustment.""" + + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. + + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ diff --git a/src/orb/types/shared/monetary_usage_discount_adjustment.py b/src/orb/types/shared/monetary_usage_discount_adjustment.py new file mode 100644 index 00000000..3a3c959a --- /dev/null +++ b/src/orb/types/shared/monetary_usage_discount_adjustment.py @@ -0,0 +1,56 @@ +# 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__ = ["MonetaryUsageDiscountAdjustment", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class MonetaryUsageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["usage_discount"] + + amount: str + """The value applied by an adjustment.""" + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + filters: List[Filter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, false for adjustments that + apply to only one price. + """ + + reason: Optional[str] = None + """The reason for the adjustment.""" + + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. + + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ + + usage_discount: float + """ + The number of usage units by which to discount the price this adjustment applies + to in a given billing period. + """ diff --git a/src/orb/types/shared/new_allocation_price.py b/src/orb/types/shared/new_allocation_price.py new file mode 100644 index 00000000..7f6c1355 --- /dev/null +++ b/src/orb/types/shared/new_allocation_price.py @@ -0,0 +1,72 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .custom_expiration import CustomExpiration + +__all__ = ["NewAllocationPrice", "Filter"] + + +class Filter(BaseModel): + """A PriceFilter that only allows item_id field for block filters.""" + + field: Literal["item_id"] + """The property of the price the block applies to. Only item_id is supported.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class NewAllocationPrice(BaseModel): + amount: str + """An amount of the currency to allocate to the customer at the specified cadence.""" + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual"] + """The cadence at which to allocate the amount to the customer.""" + + currency: str + """ + An ISO 4217 currency string or a custom pricing unit identifier in which to bill + this price. + """ + + custom_expiration: Optional[CustomExpiration] = None + """The custom expiration for the allocation.""" + + expires_at_end_of_cadence: Optional[bool] = None + """ + Whether the allocated amount should expire at the end of the cadence or roll + over to the next period. Set to null if using custom_expiration. + """ + + filters: Optional[List[Filter]] = None + """The filters that determine which items the allocation applies to.""" + + item_id: Optional[str] = None + """ + The item ID that line items representing charges for this allocation will be + associated with. If not provided, the default allocation item for the currency + will be used (e.g. 'Included Allocation (USD)'). + """ + + license_type_id: Optional[str] = None + """The license type ID to associate the price with license allocation.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ + + per_unit_cost_basis: Optional[str] = None + """The (per-unit) cost basis of each created block. + + If non-zero, a customer will be invoiced according to the quantity and per unit + cost basis specified for the allocation each cadence. + """ diff --git a/src/orb/types/shared/new_amount_discount.py b/src/orb/types/shared/new_amount_discount.py new file mode 100644 index 00000000..6e811d1c --- /dev/null +++ b/src/orb/types/shared/new_amount_discount.py @@ -0,0 +1,49 @@ +# 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__ = ["NewAmountDiscount", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class NewAmountDiscount(BaseModel): + adjustment_type: Literal["amount_discount"] + + amount_discount: str + + applies_to_all: Optional[Literal[True]] = None + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[List[str]] = None + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[List[str]] = None + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] = None + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[List[Filter]] = None + """A list of filters that determine which prices this adjustment will apply to.""" + + is_invoice_level: Optional[bool] = None + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] = None + """If set, only prices of the specified type will have the adjustment applied.""" diff --git a/src/orb/types/shared/new_billing_cycle_configuration.py b/src/orb/types/shared/new_billing_cycle_configuration.py new file mode 100644 index 00000000..35bc31b9 --- /dev/null +++ b/src/orb/types/shared/new_billing_cycle_configuration.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["NewBillingCycleConfiguration"] + + +class NewBillingCycleConfiguration(BaseModel): + duration: int + """The duration of the billing period.""" + + duration_unit: Literal["day", "month"] + """The unit of billing period duration.""" diff --git a/src/orb/types/shared/new_dimensional_price_configuration.py b/src/orb/types/shared/new_dimensional_price_configuration.py new file mode 100644 index 00000000..00de969c --- /dev/null +++ b/src/orb/types/shared/new_dimensional_price_configuration.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["NewDimensionalPriceConfiguration"] + + +class NewDimensionalPriceConfiguration(BaseModel): + dimension_values: List[str] + """ + The list of dimension values matching (in order) the dimensions of the price + group + """ + + dimensional_price_group_id: Optional[str] = None + """The id of the dimensional price group to include this price in""" + + external_dimensional_price_group_id: Optional[str] = None + """The external id of the dimensional price group to include this price in""" diff --git a/src/orb/types/shared/new_floating_bulk_price.py b/src/orb/types/shared/new_floating_bulk_price.py new file mode 100644 index 00000000..b9a72b3d --- /dev/null +++ b/src/orb/types/shared/new_floating_bulk_price.py @@ -0,0 +1,95 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .bulk_config import BulkConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingBulkPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingBulkPrice(BaseModel): + bulk_config: BulkConfig + """Configuration for bulk pricing""" + + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["bulk"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_bulk_with_proration_price.py b/src/orb/types/shared/new_floating_bulk_with_proration_price.py new file mode 100644 index 00000000..024f31aa --- /dev/null +++ b/src/orb/types/shared/new_floating_bulk_with_proration_price.py @@ -0,0 +1,117 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingBulkWithProrationPrice", + "BulkWithProrationConfig", + "BulkWithProrationConfigTier", + "ConversionRateConfig", +] + + +class BulkWithProrationConfigTier(BaseModel): + """Configuration for a single bulk pricing tier with proration""" + + unit_amount: str + """Cost per unit""" + + tier_lower_bound: Optional[str] = None + """The lower bound for this tier""" + + +class BulkWithProrationConfig(BaseModel): + """Configuration for bulk_with_proration pricing""" + + tiers: List[BulkWithProrationConfigTier] + """Bulk tiers for rating based on total usage volume""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingBulkWithProrationPrice(BaseModel): + bulk_with_proration_config: BulkWithProrationConfig + """Configuration for bulk_with_proration pricing""" + + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["bulk_with_proration"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_cumulative_grouped_bulk_price.py b/src/orb/types/shared/new_floating_cumulative_grouped_bulk_price.py new file mode 100644 index 00000000..dbdb3118 --- /dev/null +++ b/src/orb/types/shared/new_floating_cumulative_grouped_bulk_price.py @@ -0,0 +1,122 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingCumulativeGroupedBulkPrice", + "CumulativeGroupedBulkConfig", + "CumulativeGroupedBulkConfigDimensionValue", + "ConversionRateConfig", +] + + +class CumulativeGroupedBulkConfigDimensionValue(BaseModel): + """Configuration for a dimension value entry""" + + grouping_key: str + """Grouping key value""" + + tier_lower_bound: str + """Tier lower bound""" + + unit_amount: str + """Unit amount for this combination""" + + +class CumulativeGroupedBulkConfig(BaseModel): + """Configuration for cumulative_grouped_bulk pricing""" + + dimension_values: List[CumulativeGroupedBulkConfigDimensionValue] + """Each tier lower bound must have the same group of values.""" + + group: str + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingCumulativeGroupedBulkPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + cumulative_grouped_bulk_config: CumulativeGroupedBulkConfig + """Configuration for cumulative_grouped_bulk pricing""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["cumulative_grouped_bulk"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_grouped_allocation_price.py b/src/orb/types/shared/new_floating_grouped_allocation_price.py new file mode 100644 index 00000000..065750e8 --- /dev/null +++ b/src/orb/types/shared/new_floating_grouped_allocation_price.py @@ -0,0 +1,108 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingGroupedAllocationPrice", "GroupedAllocationConfig", "ConversionRateConfig"] + + +class GroupedAllocationConfig(BaseModel): + """Configuration for grouped_allocation pricing""" + + allocation: str + """Usage allocation per group""" + + grouping_key: str + """How to determine the groups that should each be allocated some quantity""" + + overage_unit_rate: str + """Unit rate for post-allocation""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingGroupedAllocationPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + grouped_allocation_config: GroupedAllocationConfig + """Configuration for grouped_allocation pricing""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["grouped_allocation"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_grouped_tiered_package_price.py b/src/orb/types/shared/new_floating_grouped_tiered_package_price.py new file mode 100644 index 00000000..27584cf1 --- /dev/null +++ b/src/orb/types/shared/new_floating_grouped_tiered_package_price.py @@ -0,0 +1,124 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingGroupedTieredPackagePrice", + "GroupedTieredPackageConfig", + "GroupedTieredPackageConfigTier", + "ConversionRateConfig", +] + + +class GroupedTieredPackageConfigTier(BaseModel): + """Configuration for a single tier""" + + per_unit: str + """Per package""" + + tier_lower_bound: str + + +class GroupedTieredPackageConfig(BaseModel): + """Configuration for grouped_tiered_package pricing""" + + grouping_key: str + """The event property used to group before tiering""" + + package_size: str + + tiers: List[GroupedTieredPackageConfigTier] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. + """ + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingGroupedTieredPackagePrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + grouped_tiered_package_config: GroupedTieredPackageConfig + """Configuration for grouped_tiered_package pricing""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["grouped_tiered_package"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_grouped_tiered_price.py b/src/orb/types/shared/new_floating_grouped_tiered_price.py new file mode 100644 index 00000000..39c48ccc --- /dev/null +++ b/src/orb/types/shared/new_floating_grouped_tiered_price.py @@ -0,0 +1,117 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingGroupedTieredPrice", "GroupedTieredConfig", "GroupedTieredConfigTier", "ConversionRateConfig"] + + +class GroupedTieredConfigTier(BaseModel): + """Configuration for a single tier""" + + tier_lower_bound: str + + unit_amount: str + """Per unit amount""" + + +class GroupedTieredConfig(BaseModel): + """Configuration for grouped_tiered pricing""" + + grouping_key: str + """The billable metric property used to group before tiering""" + + tiers: List[GroupedTieredConfigTier] + """ + Apply tiered pricing to each segment generated after grouping with the provided + key + """ + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingGroupedTieredPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + grouped_tiered_config: GroupedTieredConfig + """Configuration for grouped_tiered pricing""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["grouped_tiered"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_grouped_with_metered_minimum_price.py b/src/orb/types/shared/new_floating_grouped_with_metered_minimum_price.py new file mode 100644 index 00000000..1c757ddd --- /dev/null +++ b/src/orb/types/shared/new_floating_grouped_with_metered_minimum_price.py @@ -0,0 +1,146 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingGroupedWithMeteredMinimumPrice", + "GroupedWithMeteredMinimumConfig", + "GroupedWithMeteredMinimumConfigScalingFactor", + "GroupedWithMeteredMinimumConfigUnitAmount", + "ConversionRateConfig", +] + + +class GroupedWithMeteredMinimumConfigScalingFactor(BaseModel): + """Configuration for a scaling factor""" + + scaling_factor: str + + scaling_value: str + + +class GroupedWithMeteredMinimumConfigUnitAmount(BaseModel): + """Configuration for a unit amount""" + + pricing_value: str + + unit_amount: str + """Per unit amount""" + + +class GroupedWithMeteredMinimumConfig(BaseModel): + """Configuration for grouped_with_metered_minimum pricing""" + + grouping_key: str + """Used to partition the usage into groups. + + The minimum amount is applied to each group. + """ + + minimum_unit_amount: str + """The minimum amount to charge per group per unit""" + + pricing_key: str + """Used to determine the unit rate""" + + scaling_factors: List[GroupedWithMeteredMinimumConfigScalingFactor] + """Scale the unit rates by the scaling factor.""" + + scaling_key: str + """Used to determine the unit rate scaling factor""" + + unit_amounts: List[GroupedWithMeteredMinimumConfigUnitAmount] + """Apply per unit pricing to each pricing value. + + The minimum amount is applied any unmatched usage. + """ + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingGroupedWithMeteredMinimumPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + grouped_with_metered_minimum_config: GroupedWithMeteredMinimumConfig + """Configuration for grouped_with_metered_minimum pricing""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["grouped_with_metered_minimum"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_grouped_with_prorated_minimum_price.py b/src/orb/types/shared/new_floating_grouped_with_prorated_minimum_price.py new file mode 100644 index 00000000..236611b9 --- /dev/null +++ b/src/orb/types/shared/new_floating_grouped_with_prorated_minimum_price.py @@ -0,0 +1,108 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingGroupedWithProratedMinimumPrice", "GroupedWithProratedMinimumConfig", "ConversionRateConfig"] + + +class GroupedWithProratedMinimumConfig(BaseModel): + """Configuration for grouped_with_prorated_minimum pricing""" + + grouping_key: str + """How to determine the groups that should each have a minimum""" + + minimum: str + """The minimum amount to charge per group""" + + unit_rate: str + """The amount to charge per unit""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingGroupedWithProratedMinimumPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + grouped_with_prorated_minimum_config: GroupedWithProratedMinimumConfig + """Configuration for grouped_with_prorated_minimum pricing""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["grouped_with_prorated_minimum"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_matrix_price.py b/src/orb/types/shared/new_floating_matrix_price.py new file mode 100644 index 00000000..ff12bc14 --- /dev/null +++ b/src/orb/types/shared/new_floating_matrix_price.py @@ -0,0 +1,95 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .matrix_config import MatrixConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingMatrixPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingMatrixPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + matrix_config: MatrixConfig + """Configuration for matrix pricing""" + + price_model_type: Literal["matrix"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_matrix_with_allocation_price.py b/src/orb/types/shared/new_floating_matrix_with_allocation_price.py new file mode 100644 index 00000000..688793ad --- /dev/null +++ b/src/orb/types/shared/new_floating_matrix_with_allocation_price.py @@ -0,0 +1,95 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .matrix_with_allocation_config import MatrixWithAllocationConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingMatrixWithAllocationPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingMatrixWithAllocationPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + matrix_with_allocation_config: MatrixWithAllocationConfig + """Configuration for matrix_with_allocation pricing""" + + price_model_type: Literal["matrix_with_allocation"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_matrix_with_display_name_price.py b/src/orb/types/shared/new_floating_matrix_with_display_name_price.py new file mode 100644 index 00000000..8748b1fa --- /dev/null +++ b/src/orb/types/shared/new_floating_matrix_with_display_name_price.py @@ -0,0 +1,123 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingMatrixWithDisplayNamePrice", + "MatrixWithDisplayNameConfig", + "MatrixWithDisplayNameConfigUnitAmount", + "ConversionRateConfig", +] + + +class MatrixWithDisplayNameConfigUnitAmount(BaseModel): + """Configuration for a unit amount item""" + + dimension_value: str + """The dimension value""" + + display_name: str + """Display name for this dimension value""" + + unit_amount: str + """Per unit amount""" + + +class MatrixWithDisplayNameConfig(BaseModel): + """Configuration for matrix_with_display_name pricing""" + + dimension: str + """Used to determine the unit rate""" + + unit_amounts: List[MatrixWithDisplayNameConfigUnitAmount] + """Apply per unit pricing to each dimension value""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingMatrixWithDisplayNamePrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + matrix_with_display_name_config: MatrixWithDisplayNameConfig + """Configuration for matrix_with_display_name pricing""" + + price_model_type: Literal["matrix_with_display_name"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_max_group_tiered_package_price.py b/src/orb/types/shared/new_floating_max_group_tiered_package_price.py new file mode 100644 index 00000000..9603e115 --- /dev/null +++ b/src/orb/types/shared/new_floating_max_group_tiered_package_price.py @@ -0,0 +1,123 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingMaxGroupTieredPackagePrice", + "MaxGroupTieredPackageConfig", + "MaxGroupTieredPackageConfigTier", + "ConversionRateConfig", +] + + +class MaxGroupTieredPackageConfigTier(BaseModel): + """Configuration for a single tier""" + + tier_lower_bound: str + + unit_amount: str + """Per unit amount""" + + +class MaxGroupTieredPackageConfig(BaseModel): + """Configuration for max_group_tiered_package pricing""" + + grouping_key: str + """ + The event property used to group before tiering the group with the highest value + """ + + package_size: str + + tiers: List[MaxGroupTieredPackageConfigTier] + """Apply tiered pricing to the largest group after grouping with the provided key.""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingMaxGroupTieredPackagePrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + max_group_tiered_package_config: MaxGroupTieredPackageConfig + """Configuration for max_group_tiered_package pricing""" + + price_model_type: Literal["max_group_tiered_package"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_minimum_composite_price.py b/src/orb/types/shared/new_floating_minimum_composite_price.py new file mode 100644 index 00000000..4c210ac3 --- /dev/null +++ b/src/orb/types/shared/new_floating_minimum_composite_price.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingMinimumCompositePrice", "MinimumCompositeConfig", "ConversionRateConfig"] + + +class MinimumCompositeConfig(BaseModel): + """Configuration for minimum_composite pricing""" + + minimum_amount: str + """The minimum amount to apply""" + + prorated: Optional[bool] = None + """If true, subtotals from this price are prorated based on the service period""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingMinimumCompositePrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + minimum_composite_config: MinimumCompositeConfig + """Configuration for minimum_composite pricing""" + + price_model_type: Literal["minimum_composite"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_package_price.py b/src/orb/types/shared/new_floating_package_price.py new file mode 100644 index 00000000..e0ccf470 --- /dev/null +++ b/src/orb/types/shared/new_floating_package_price.py @@ -0,0 +1,95 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .package_config import PackageConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingPackagePrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingPackagePrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["package"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + package_config: PackageConfig + """Configuration for package pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_package_with_allocation_price.py b/src/orb/types/shared/new_floating_package_with_allocation_price.py new file mode 100644 index 00000000..07c5a9e1 --- /dev/null +++ b/src/orb/types/shared/new_floating_package_with_allocation_price.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingPackageWithAllocationPrice", "PackageWithAllocationConfig", "ConversionRateConfig"] + + +class PackageWithAllocationConfig(BaseModel): + """Configuration for package_with_allocation pricing""" + + allocation: str + + package_amount: str + + package_size: str + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingPackageWithAllocationPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["package_with_allocation"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + package_with_allocation_config: PackageWithAllocationConfig + """Configuration for package_with_allocation pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_scalable_matrix_with_tiered_pricing_price.py b/src/orb/types/shared/new_floating_scalable_matrix_with_tiered_pricing_price.py new file mode 100644 index 00000000..2a13555d --- /dev/null +++ b/src/orb/types/shared/new_floating_scalable_matrix_with_tiered_pricing_price.py @@ -0,0 +1,134 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingScalableMatrixWithTieredPricingPrice", + "ScalableMatrixWithTieredPricingConfig", + "ScalableMatrixWithTieredPricingConfigMatrixScalingFactor", + "ScalableMatrixWithTieredPricingConfigTier", + "ConversionRateConfig", +] + + +class ScalableMatrixWithTieredPricingConfigMatrixScalingFactor(BaseModel): + """Configuration for a single matrix scaling factor""" + + first_dimension_value: str + + scaling_factor: str + + second_dimension_value: Optional[str] = None + + +class ScalableMatrixWithTieredPricingConfigTier(BaseModel): + """Configuration for a single tier entry with business logic""" + + tier_lower_bound: str + + unit_amount: str + + +class ScalableMatrixWithTieredPricingConfig(BaseModel): + """Configuration for scalable_matrix_with_tiered_pricing pricing""" + + first_dimension: str + """Used for the scalable matrix first dimension""" + + matrix_scaling_factors: List[ScalableMatrixWithTieredPricingConfigMatrixScalingFactor] + """Apply a scaling factor to each dimension""" + + tiers: List[ScalableMatrixWithTieredPricingConfigTier] + + second_dimension: Optional[str] = None + """Used for the scalable matrix second dimension (optional)""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingScalableMatrixWithTieredPricingPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["scalable_matrix_with_tiered_pricing"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + scalable_matrix_with_tiered_pricing_config: ScalableMatrixWithTieredPricingConfig + """Configuration for scalable_matrix_with_tiered_pricing pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_scalable_matrix_with_unit_pricing_price.py b/src/orb/types/shared/new_floating_scalable_matrix_with_unit_pricing_price.py new file mode 100644 index 00000000..e1cc30a2 --- /dev/null +++ b/src/orb/types/shared/new_floating_scalable_matrix_with_unit_pricing_price.py @@ -0,0 +1,132 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingScalableMatrixWithUnitPricingPrice", + "ScalableMatrixWithUnitPricingConfig", + "ScalableMatrixWithUnitPricingConfigMatrixScalingFactor", + "ConversionRateConfig", +] + + +class ScalableMatrixWithUnitPricingConfigMatrixScalingFactor(BaseModel): + """Configuration for a single matrix scaling factor""" + + first_dimension_value: str + + scaling_factor: str + + second_dimension_value: Optional[str] = None + + +class ScalableMatrixWithUnitPricingConfig(BaseModel): + """Configuration for scalable_matrix_with_unit_pricing pricing""" + + first_dimension: str + """Used to determine the unit rate""" + + matrix_scaling_factors: List[ScalableMatrixWithUnitPricingConfigMatrixScalingFactor] + """Apply a scaling factor to each dimension""" + + unit_price: str + """The final unit price to rate against the output of the matrix""" + + grouping_key: Optional[str] = None + """The property used to group this price""" + + prorate: Optional[bool] = None + """If true, the unit price will be prorated to the billing period""" + + second_dimension: Optional[str] = None + """Used to determine the unit rate (optional)""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingScalableMatrixWithUnitPricingPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["scalable_matrix_with_unit_pricing"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + scalable_matrix_with_unit_pricing_config: ScalableMatrixWithUnitPricingConfig + """Configuration for scalable_matrix_with_unit_pricing pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_threshold_total_amount_price.py b/src/orb/types/shared/new_floating_threshold_total_amount_price.py new file mode 100644 index 00000000..be1c1229 --- /dev/null +++ b/src/orb/types/shared/new_floating_threshold_total_amount_price.py @@ -0,0 +1,122 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingThresholdTotalAmountPrice", + "ThresholdTotalAmountConfig", + "ThresholdTotalAmountConfigConsumptionTable", + "ConversionRateConfig", +] + + +class ThresholdTotalAmountConfigConsumptionTable(BaseModel): + """Configuration for a single threshold""" + + threshold: str + + total_amount: str + """Total amount for this threshold""" + + +class ThresholdTotalAmountConfig(BaseModel): + """Configuration for threshold_total_amount pricing""" + + consumption_table: List[ThresholdTotalAmountConfigConsumptionTable] + """ + When the quantity consumed passes a provided threshold, the configured total + will be charged + """ + + prorate: Optional[bool] = None + """If true, the unit price will be prorated to the billing period""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingThresholdTotalAmountPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["threshold_total_amount"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + threshold_total_amount_config: ThresholdTotalAmountConfig + """Configuration for threshold_total_amount pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_tiered_package_price.py b/src/orb/types/shared/new_floating_tiered_package_price.py new file mode 100644 index 00000000..4509b662 --- /dev/null +++ b/src/orb/types/shared/new_floating_tiered_package_price.py @@ -0,0 +1,118 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingTieredPackagePrice", "TieredPackageConfig", "TieredPackageConfigTier", "ConversionRateConfig"] + + +class TieredPackageConfigTier(BaseModel): + """Configuration for a single tier with business logic""" + + per_unit: str + """Price per package""" + + tier_lower_bound: str + + +class TieredPackageConfig(BaseModel): + """Configuration for tiered_package pricing""" + + package_size: str + + tiers: List[TieredPackageConfigTier] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. The tier bounds are defined + based on the total quantity rather than the number of packages, so they must be + multiples of the package size. + """ + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingTieredPackagePrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["tiered_package"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + tiered_package_config: TieredPackageConfig + """Configuration for tiered_package pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_tiered_package_with_minimum_price.py b/src/orb/types/shared/new_floating_tiered_package_with_minimum_price.py new file mode 100644 index 00000000..6d753c36 --- /dev/null +++ b/src/orb/types/shared/new_floating_tiered_package_with_minimum_price.py @@ -0,0 +1,122 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingTieredPackageWithMinimumPrice", + "TieredPackageWithMinimumConfig", + "TieredPackageWithMinimumConfigTier", + "ConversionRateConfig", +] + + +class TieredPackageWithMinimumConfigTier(BaseModel): + """Configuration for a single tier""" + + minimum_amount: str + + per_unit: str + + tier_lower_bound: str + + +class TieredPackageWithMinimumConfig(BaseModel): + """Configuration for tiered_package_with_minimum pricing""" + + package_size: float + + tiers: List[TieredPackageWithMinimumConfigTier] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. + """ + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingTieredPackageWithMinimumPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["tiered_package_with_minimum"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + tiered_package_with_minimum_config: TieredPackageWithMinimumConfig + """Configuration for tiered_package_with_minimum pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_tiered_price.py b/src/orb/types/shared/new_floating_tiered_price.py new file mode 100644 index 00000000..6fafe7f4 --- /dev/null +++ b/src/orb/types/shared/new_floating_tiered_price.py @@ -0,0 +1,95 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .tiered_config import TieredConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingTieredPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingTieredPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["tiered"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + tiered_config: TieredConfig + """Configuration for tiered pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_tiered_with_minimum_price.py b/src/orb/types/shared/new_floating_tiered_with_minimum_price.py new file mode 100644 index 00000000..4f1b96f0 --- /dev/null +++ b/src/orb/types/shared/new_floating_tiered_with_minimum_price.py @@ -0,0 +1,127 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingTieredWithMinimumPrice", + "TieredWithMinimumConfig", + "TieredWithMinimumConfigTier", + "ConversionRateConfig", +] + + +class TieredWithMinimumConfigTier(BaseModel): + """Configuration for a single tier""" + + minimum_amount: str + + tier_lower_bound: str + + unit_amount: str + """Per unit amount""" + + +class TieredWithMinimumConfig(BaseModel): + """Configuration for tiered_with_minimum pricing""" + + tiers: List[TieredWithMinimumConfigTier] + """Tiered pricing with a minimum amount dependent on the volume tier. + + Tiers are defined using exclusive lower bounds. + """ + + hide_zero_amount_tiers: Optional[bool] = None + """If true, tiers with an accrued amount of 0 will not be included in the rating.""" + + prorate: Optional[bool] = None + """If true, the unit price will be prorated to the billing period""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingTieredWithMinimumPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["tiered_with_minimum"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + tiered_with_minimum_config: TieredWithMinimumConfig + """Configuration for tiered_with_minimum pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_tiered_with_proration_price.py b/src/orb/types/shared/new_floating_tiered_with_proration_price.py new file mode 100644 index 00000000..4b6caab8 --- /dev/null +++ b/src/orb/types/shared/new_floating_tiered_with_proration_price.py @@ -0,0 +1,120 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingTieredWithProrationPrice", + "TieredWithProrationConfig", + "TieredWithProrationConfigTier", + "ConversionRateConfig", +] + + +class TieredWithProrationConfigTier(BaseModel): + """Configuration for a single tiered with proration tier""" + + tier_lower_bound: str + """Inclusive tier starting value""" + + unit_amount: str + """Amount per unit""" + + +class TieredWithProrationConfig(BaseModel): + """Configuration for tiered_with_proration pricing""" + + tiers: List[TieredWithProrationConfigTier] + """ + Tiers for rating based on total usage quantities into the specified tier with + proration + """ + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingTieredWithProrationPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["tiered_with_proration"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + tiered_with_proration_config: TieredWithProrationConfig + """Configuration for tiered_with_proration pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_unit_price.py b/src/orb/types/shared/new_floating_unit_price.py new file mode 100644 index 00000000..852121cb --- /dev/null +++ b/src/orb/types/shared/new_floating_unit_price.py @@ -0,0 +1,95 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_config import UnitConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingUnitPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingUnitPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["unit"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + unit_config: UnitConfig + """Configuration for unit pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_unit_with_percent_price.py b/src/orb/types/shared/new_floating_unit_with_percent_price.py new file mode 100644 index 00000000..4d91d40d --- /dev/null +++ b/src/orb/types/shared/new_floating_unit_with_percent_price.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingUnitWithPercentPrice", "UnitWithPercentConfig", "ConversionRateConfig"] + + +class UnitWithPercentConfig(BaseModel): + """Configuration for unit_with_percent pricing""" + + percent: str + """What percent, out of 100, of the calculated total to charge""" + + unit_amount: str + """Rate per unit of usage""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingUnitWithPercentPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["unit_with_percent"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + unit_with_percent_config: UnitWithPercentConfig + """Configuration for unit_with_percent pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_floating_unit_with_proration_price.py b/src/orb/types/shared/new_floating_unit_with_proration_price.py new file mode 100644 index 00000000..2c6425a8 --- /dev/null +++ b/src/orb/types/shared/new_floating_unit_with_proration_price.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingUnitWithProrationPrice", "UnitWithProrationConfig", "ConversionRateConfig"] + + +class UnitWithProrationConfig(BaseModel): + """Configuration for unit_with_proration pricing""" + + unit_amount: str + """Rate per unit of usage""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewFloatingUnitWithProrationPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + currency: str + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["unit_with_proration"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + unit_with_proration_config: UnitWithProrationConfig + """Configuration for unit_with_proration pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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`. + """ diff --git a/src/orb/types/shared/new_maximum.py b/src/orb/types/shared/new_maximum.py new file mode 100644 index 00000000..3200e6e0 --- /dev/null +++ b/src/orb/types/shared/new_maximum.py @@ -0,0 +1,49 @@ +# 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__ = ["NewMaximum", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class NewMaximum(BaseModel): + adjustment_type: Literal["maximum"] + + maximum_amount: str + + applies_to_all: Optional[Literal[True]] = None + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[List[str]] = None + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[List[str]] = None + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] = None + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[List[Filter]] = None + """A list of filters that determine which prices this adjustment will apply to.""" + + is_invoice_level: Optional[bool] = None + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] = None + """If set, only prices of the specified type will have the adjustment applied.""" diff --git a/src/orb/types/shared/new_minimum.py b/src/orb/types/shared/new_minimum.py new file mode 100644 index 00000000..03ffecf9 --- /dev/null +++ b/src/orb/types/shared/new_minimum.py @@ -0,0 +1,52 @@ +# 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__ = ["NewMinimum", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class NewMinimum(BaseModel): + adjustment_type: Literal["minimum"] + + item_id: str + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: str + + applies_to_all: Optional[Literal[True]] = None + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[List[str]] = None + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[List[str]] = None + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] = None + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[List[Filter]] = None + """A list of filters that determine which prices this adjustment will apply to.""" + + is_invoice_level: Optional[bool] = None + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] = None + """If set, only prices of the specified type will have the adjustment applied.""" diff --git a/src/orb/types/shared/new_percentage_discount.py b/src/orb/types/shared/new_percentage_discount.py new file mode 100644 index 00000000..675ff1f8 --- /dev/null +++ b/src/orb/types/shared/new_percentage_discount.py @@ -0,0 +1,49 @@ +# 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__ = ["NewPercentageDiscount", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class NewPercentageDiscount(BaseModel): + adjustment_type: Literal["percentage_discount"] + + percentage_discount: float + + applies_to_all: Optional[Literal[True]] = None + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[List[str]] = None + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[List[str]] = None + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] = None + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[List[Filter]] = None + """A list of filters that determine which prices this adjustment will apply to.""" + + is_invoice_level: Optional[bool] = None + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] = None + """If set, only prices of the specified type will have the adjustment applied.""" diff --git a/src/orb/types/shared/new_plan_bulk_price.py b/src/orb/types/shared/new_plan_bulk_price.py new file mode 100644 index 00000000..06d31df3 --- /dev/null +++ b/src/orb/types/shared/new_plan_bulk_price.py @@ -0,0 +1,104 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .bulk_config import BulkConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanBulkPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanBulkPrice(BaseModel): + bulk_config: BulkConfig + """Configuration for bulk pricing""" + + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["bulk"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_bulk_with_proration_price.py b/src/orb/types/shared/new_plan_bulk_with_proration_price.py new file mode 100644 index 00000000..0710cdf4 --- /dev/null +++ b/src/orb/types/shared/new_plan_bulk_with_proration_price.py @@ -0,0 +1,126 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanBulkWithProrationPrice", + "BulkWithProrationConfig", + "BulkWithProrationConfigTier", + "ConversionRateConfig", +] + + +class BulkWithProrationConfigTier(BaseModel): + """Configuration for a single bulk pricing tier with proration""" + + unit_amount: str + """Cost per unit""" + + tier_lower_bound: Optional[str] = None + """The lower bound for this tier""" + + +class BulkWithProrationConfig(BaseModel): + """Configuration for bulk_with_proration pricing""" + + tiers: List[BulkWithProrationConfigTier] + """Bulk tiers for rating based on total usage volume""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanBulkWithProrationPrice(BaseModel): + bulk_with_proration_config: BulkWithProrationConfig + """Configuration for bulk_with_proration pricing""" + + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["bulk_with_proration"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_cumulative_grouped_bulk_price.py b/src/orb/types/shared/new_plan_cumulative_grouped_bulk_price.py new file mode 100644 index 00000000..bdf75853 --- /dev/null +++ b/src/orb/types/shared/new_plan_cumulative_grouped_bulk_price.py @@ -0,0 +1,131 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanCumulativeGroupedBulkPrice", + "CumulativeGroupedBulkConfig", + "CumulativeGroupedBulkConfigDimensionValue", + "ConversionRateConfig", +] + + +class CumulativeGroupedBulkConfigDimensionValue(BaseModel): + """Configuration for a dimension value entry""" + + grouping_key: str + """Grouping key value""" + + tier_lower_bound: str + """Tier lower bound""" + + unit_amount: str + """Unit amount for this combination""" + + +class CumulativeGroupedBulkConfig(BaseModel): + """Configuration for cumulative_grouped_bulk pricing""" + + dimension_values: List[CumulativeGroupedBulkConfigDimensionValue] + """Each tier lower bound must have the same group of values.""" + + group: str + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanCumulativeGroupedBulkPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + cumulative_grouped_bulk_config: CumulativeGroupedBulkConfig + """Configuration for cumulative_grouped_bulk pricing""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["cumulative_grouped_bulk"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_grouped_allocation_price.py b/src/orb/types/shared/new_plan_grouped_allocation_price.py new file mode 100644 index 00000000..1ef99faa --- /dev/null +++ b/src/orb/types/shared/new_plan_grouped_allocation_price.py @@ -0,0 +1,117 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanGroupedAllocationPrice", "GroupedAllocationConfig", "ConversionRateConfig"] + + +class GroupedAllocationConfig(BaseModel): + """Configuration for grouped_allocation pricing""" + + allocation: str + """Usage allocation per group""" + + grouping_key: str + """How to determine the groups that should each be allocated some quantity""" + + overage_unit_rate: str + """Unit rate for post-allocation""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanGroupedAllocationPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + grouped_allocation_config: GroupedAllocationConfig + """Configuration for grouped_allocation pricing""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["grouped_allocation"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_grouped_tiered_package_price.py b/src/orb/types/shared/new_plan_grouped_tiered_package_price.py new file mode 100644 index 00000000..81b6a8c0 --- /dev/null +++ b/src/orb/types/shared/new_plan_grouped_tiered_package_price.py @@ -0,0 +1,133 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanGroupedTieredPackagePrice", + "GroupedTieredPackageConfig", + "GroupedTieredPackageConfigTier", + "ConversionRateConfig", +] + + +class GroupedTieredPackageConfigTier(BaseModel): + """Configuration for a single tier""" + + per_unit: str + """Per package""" + + tier_lower_bound: str + + +class GroupedTieredPackageConfig(BaseModel): + """Configuration for grouped_tiered_package pricing""" + + grouping_key: str + """The event property used to group before tiering""" + + package_size: str + + tiers: List[GroupedTieredPackageConfigTier] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. + """ + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanGroupedTieredPackagePrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + grouped_tiered_package_config: GroupedTieredPackageConfig + """Configuration for grouped_tiered_package pricing""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["grouped_tiered_package"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_grouped_tiered_price.py b/src/orb/types/shared/new_plan_grouped_tiered_price.py new file mode 100644 index 00000000..769794f9 --- /dev/null +++ b/src/orb/types/shared/new_plan_grouped_tiered_price.py @@ -0,0 +1,126 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanGroupedTieredPrice", "GroupedTieredConfig", "GroupedTieredConfigTier", "ConversionRateConfig"] + + +class GroupedTieredConfigTier(BaseModel): + """Configuration for a single tier""" + + tier_lower_bound: str + + unit_amount: str + """Per unit amount""" + + +class GroupedTieredConfig(BaseModel): + """Configuration for grouped_tiered pricing""" + + grouping_key: str + """The billable metric property used to group before tiering""" + + tiers: List[GroupedTieredConfigTier] + """ + Apply tiered pricing to each segment generated after grouping with the provided + key + """ + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanGroupedTieredPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + grouped_tiered_config: GroupedTieredConfig + """Configuration for grouped_tiered pricing""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["grouped_tiered"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_grouped_with_metered_minimum_price.py b/src/orb/types/shared/new_plan_grouped_with_metered_minimum_price.py new file mode 100644 index 00000000..e3a2472f --- /dev/null +++ b/src/orb/types/shared/new_plan_grouped_with_metered_minimum_price.py @@ -0,0 +1,155 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanGroupedWithMeteredMinimumPrice", + "GroupedWithMeteredMinimumConfig", + "GroupedWithMeteredMinimumConfigScalingFactor", + "GroupedWithMeteredMinimumConfigUnitAmount", + "ConversionRateConfig", +] + + +class GroupedWithMeteredMinimumConfigScalingFactor(BaseModel): + """Configuration for a scaling factor""" + + scaling_factor: str + + scaling_value: str + + +class GroupedWithMeteredMinimumConfigUnitAmount(BaseModel): + """Configuration for a unit amount""" + + pricing_value: str + + unit_amount: str + """Per unit amount""" + + +class GroupedWithMeteredMinimumConfig(BaseModel): + """Configuration for grouped_with_metered_minimum pricing""" + + grouping_key: str + """Used to partition the usage into groups. + + The minimum amount is applied to each group. + """ + + minimum_unit_amount: str + """The minimum amount to charge per group per unit""" + + pricing_key: str + """Used to determine the unit rate""" + + scaling_factors: List[GroupedWithMeteredMinimumConfigScalingFactor] + """Scale the unit rates by the scaling factor.""" + + scaling_key: str + """Used to determine the unit rate scaling factor""" + + unit_amounts: List[GroupedWithMeteredMinimumConfigUnitAmount] + """Apply per unit pricing to each pricing value. + + The minimum amount is applied any unmatched usage. + """ + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanGroupedWithMeteredMinimumPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + grouped_with_metered_minimum_config: GroupedWithMeteredMinimumConfig + """Configuration for grouped_with_metered_minimum pricing""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["grouped_with_metered_minimum"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_grouped_with_prorated_minimum_price.py b/src/orb/types/shared/new_plan_grouped_with_prorated_minimum_price.py new file mode 100644 index 00000000..f8d62cfd --- /dev/null +++ b/src/orb/types/shared/new_plan_grouped_with_prorated_minimum_price.py @@ -0,0 +1,117 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanGroupedWithProratedMinimumPrice", "GroupedWithProratedMinimumConfig", "ConversionRateConfig"] + + +class GroupedWithProratedMinimumConfig(BaseModel): + """Configuration for grouped_with_prorated_minimum pricing""" + + grouping_key: str + """How to determine the groups that should each have a minimum""" + + minimum: str + """The minimum amount to charge per group""" + + unit_rate: str + """The amount to charge per unit""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanGroupedWithProratedMinimumPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + grouped_with_prorated_minimum_config: GroupedWithProratedMinimumConfig + """Configuration for grouped_with_prorated_minimum pricing""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["grouped_with_prorated_minimum"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_matrix_price.py b/src/orb/types/shared/new_plan_matrix_price.py new file mode 100644 index 00000000..c2df14bc --- /dev/null +++ b/src/orb/types/shared/new_plan_matrix_price.py @@ -0,0 +1,104 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .matrix_config import MatrixConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanMatrixPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanMatrixPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + matrix_config: MatrixConfig + """Configuration for matrix pricing""" + + price_model_type: Literal["matrix"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_matrix_with_allocation_price.py b/src/orb/types/shared/new_plan_matrix_with_allocation_price.py new file mode 100644 index 00000000..be33b0cb --- /dev/null +++ b/src/orb/types/shared/new_plan_matrix_with_allocation_price.py @@ -0,0 +1,104 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .matrix_with_allocation_config import MatrixWithAllocationConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanMatrixWithAllocationPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanMatrixWithAllocationPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + matrix_with_allocation_config: MatrixWithAllocationConfig + """Configuration for matrix_with_allocation pricing""" + + price_model_type: Literal["matrix_with_allocation"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_matrix_with_display_name_price.py b/src/orb/types/shared/new_plan_matrix_with_display_name_price.py new file mode 100644 index 00000000..639391b2 --- /dev/null +++ b/src/orb/types/shared/new_plan_matrix_with_display_name_price.py @@ -0,0 +1,132 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanMatrixWithDisplayNamePrice", + "MatrixWithDisplayNameConfig", + "MatrixWithDisplayNameConfigUnitAmount", + "ConversionRateConfig", +] + + +class MatrixWithDisplayNameConfigUnitAmount(BaseModel): + """Configuration for a unit amount item""" + + dimension_value: str + """The dimension value""" + + display_name: str + """Display name for this dimension value""" + + unit_amount: str + """Per unit amount""" + + +class MatrixWithDisplayNameConfig(BaseModel): + """Configuration for matrix_with_display_name pricing""" + + dimension: str + """Used to determine the unit rate""" + + unit_amounts: List[MatrixWithDisplayNameConfigUnitAmount] + """Apply per unit pricing to each dimension value""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanMatrixWithDisplayNamePrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + matrix_with_display_name_config: MatrixWithDisplayNameConfig + """Configuration for matrix_with_display_name pricing""" + + price_model_type: Literal["matrix_with_display_name"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_max_group_tiered_package_price.py b/src/orb/types/shared/new_plan_max_group_tiered_package_price.py new file mode 100644 index 00000000..06124ce3 --- /dev/null +++ b/src/orb/types/shared/new_plan_max_group_tiered_package_price.py @@ -0,0 +1,132 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanMaxGroupTieredPackagePrice", + "MaxGroupTieredPackageConfig", + "MaxGroupTieredPackageConfigTier", + "ConversionRateConfig", +] + + +class MaxGroupTieredPackageConfigTier(BaseModel): + """Configuration for a single tier""" + + tier_lower_bound: str + + unit_amount: str + """Per unit amount""" + + +class MaxGroupTieredPackageConfig(BaseModel): + """Configuration for max_group_tiered_package pricing""" + + grouping_key: str + """ + The event property used to group before tiering the group with the highest value + """ + + package_size: str + + tiers: List[MaxGroupTieredPackageConfigTier] + """Apply tiered pricing to the largest group after grouping with the provided key.""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanMaxGroupTieredPackagePrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + max_group_tiered_package_config: MaxGroupTieredPackageConfig + """Configuration for max_group_tiered_package pricing""" + + price_model_type: Literal["max_group_tiered_package"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_minimum_composite_price.py b/src/orb/types/shared/new_plan_minimum_composite_price.py new file mode 100644 index 00000000..e5730869 --- /dev/null +++ b/src/orb/types/shared/new_plan_minimum_composite_price.py @@ -0,0 +1,114 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanMinimumCompositePrice", "MinimumCompositeConfig", "ConversionRateConfig"] + + +class MinimumCompositeConfig(BaseModel): + """Configuration for minimum_composite pricing""" + + minimum_amount: str + """The minimum amount to apply""" + + prorated: Optional[bool] = None + """If true, subtotals from this price are prorated based on the service period""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanMinimumCompositePrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + minimum_composite_config: MinimumCompositeConfig + """Configuration for minimum_composite pricing""" + + price_model_type: Literal["minimum_composite"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_package_price.py b/src/orb/types/shared/new_plan_package_price.py new file mode 100644 index 00000000..b597ef69 --- /dev/null +++ b/src/orb/types/shared/new_plan_package_price.py @@ -0,0 +1,104 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .package_config import PackageConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanPackagePrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanPackagePrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["package"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + package_config: PackageConfig + """Configuration for package pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_package_with_allocation_price.py b/src/orb/types/shared/new_plan_package_with_allocation_price.py new file mode 100644 index 00000000..c323d9da --- /dev/null +++ b/src/orb/types/shared/new_plan_package_with_allocation_price.py @@ -0,0 +1,114 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanPackageWithAllocationPrice", "PackageWithAllocationConfig", "ConversionRateConfig"] + + +class PackageWithAllocationConfig(BaseModel): + """Configuration for package_with_allocation pricing""" + + allocation: str + + package_amount: str + + package_size: str + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanPackageWithAllocationPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["package_with_allocation"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + package_with_allocation_config: PackageWithAllocationConfig + """Configuration for package_with_allocation pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_scalable_matrix_with_tiered_pricing_price.py b/src/orb/types/shared/new_plan_scalable_matrix_with_tiered_pricing_price.py new file mode 100644 index 00000000..a530a99b --- /dev/null +++ b/src/orb/types/shared/new_plan_scalable_matrix_with_tiered_pricing_price.py @@ -0,0 +1,143 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanScalableMatrixWithTieredPricingPrice", + "ScalableMatrixWithTieredPricingConfig", + "ScalableMatrixWithTieredPricingConfigMatrixScalingFactor", + "ScalableMatrixWithTieredPricingConfigTier", + "ConversionRateConfig", +] + + +class ScalableMatrixWithTieredPricingConfigMatrixScalingFactor(BaseModel): + """Configuration for a single matrix scaling factor""" + + first_dimension_value: str + + scaling_factor: str + + second_dimension_value: Optional[str] = None + + +class ScalableMatrixWithTieredPricingConfigTier(BaseModel): + """Configuration for a single tier entry with business logic""" + + tier_lower_bound: str + + unit_amount: str + + +class ScalableMatrixWithTieredPricingConfig(BaseModel): + """Configuration for scalable_matrix_with_tiered_pricing pricing""" + + first_dimension: str + """Used for the scalable matrix first dimension""" + + matrix_scaling_factors: List[ScalableMatrixWithTieredPricingConfigMatrixScalingFactor] + """Apply a scaling factor to each dimension""" + + tiers: List[ScalableMatrixWithTieredPricingConfigTier] + + second_dimension: Optional[str] = None + """Used for the scalable matrix second dimension (optional)""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanScalableMatrixWithTieredPricingPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["scalable_matrix_with_tiered_pricing"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + scalable_matrix_with_tiered_pricing_config: ScalableMatrixWithTieredPricingConfig + """Configuration for scalable_matrix_with_tiered_pricing pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_scalable_matrix_with_unit_pricing_price.py b/src/orb/types/shared/new_plan_scalable_matrix_with_unit_pricing_price.py new file mode 100644 index 00000000..5ed45a08 --- /dev/null +++ b/src/orb/types/shared/new_plan_scalable_matrix_with_unit_pricing_price.py @@ -0,0 +1,141 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanScalableMatrixWithUnitPricingPrice", + "ScalableMatrixWithUnitPricingConfig", + "ScalableMatrixWithUnitPricingConfigMatrixScalingFactor", + "ConversionRateConfig", +] + + +class ScalableMatrixWithUnitPricingConfigMatrixScalingFactor(BaseModel): + """Configuration for a single matrix scaling factor""" + + first_dimension_value: str + + scaling_factor: str + + second_dimension_value: Optional[str] = None + + +class ScalableMatrixWithUnitPricingConfig(BaseModel): + """Configuration for scalable_matrix_with_unit_pricing pricing""" + + first_dimension: str + """Used to determine the unit rate""" + + matrix_scaling_factors: List[ScalableMatrixWithUnitPricingConfigMatrixScalingFactor] + """Apply a scaling factor to each dimension""" + + unit_price: str + """The final unit price to rate against the output of the matrix""" + + grouping_key: Optional[str] = None + """The property used to group this price""" + + prorate: Optional[bool] = None + """If true, the unit price will be prorated to the billing period""" + + second_dimension: Optional[str] = None + """Used to determine the unit rate (optional)""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanScalableMatrixWithUnitPricingPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["scalable_matrix_with_unit_pricing"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + scalable_matrix_with_unit_pricing_config: ScalableMatrixWithUnitPricingConfig + """Configuration for scalable_matrix_with_unit_pricing pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_threshold_total_amount_price.py b/src/orb/types/shared/new_plan_threshold_total_amount_price.py new file mode 100644 index 00000000..735438f8 --- /dev/null +++ b/src/orb/types/shared/new_plan_threshold_total_amount_price.py @@ -0,0 +1,131 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanThresholdTotalAmountPrice", + "ThresholdTotalAmountConfig", + "ThresholdTotalAmountConfigConsumptionTable", + "ConversionRateConfig", +] + + +class ThresholdTotalAmountConfigConsumptionTable(BaseModel): + """Configuration for a single threshold""" + + threshold: str + + total_amount: str + """Total amount for this threshold""" + + +class ThresholdTotalAmountConfig(BaseModel): + """Configuration for threshold_total_amount pricing""" + + consumption_table: List[ThresholdTotalAmountConfigConsumptionTable] + """ + When the quantity consumed passes a provided threshold, the configured total + will be charged + """ + + prorate: Optional[bool] = None + """If true, the unit price will be prorated to the billing period""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanThresholdTotalAmountPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["threshold_total_amount"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + threshold_total_amount_config: ThresholdTotalAmountConfig + """Configuration for threshold_total_amount pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_tiered_package_price.py b/src/orb/types/shared/new_plan_tiered_package_price.py new file mode 100644 index 00000000..7acbb481 --- /dev/null +++ b/src/orb/types/shared/new_plan_tiered_package_price.py @@ -0,0 +1,127 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanTieredPackagePrice", "TieredPackageConfig", "TieredPackageConfigTier", "ConversionRateConfig"] + + +class TieredPackageConfigTier(BaseModel): + """Configuration for a single tier with business logic""" + + per_unit: str + """Price per package""" + + tier_lower_bound: str + + +class TieredPackageConfig(BaseModel): + """Configuration for tiered_package pricing""" + + package_size: str + + tiers: List[TieredPackageConfigTier] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. The tier bounds are defined + based on the total quantity rather than the number of packages, so they must be + multiples of the package size. + """ + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanTieredPackagePrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["tiered_package"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + tiered_package_config: TieredPackageConfig + """Configuration for tiered_package pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_tiered_package_with_minimum_price.py b/src/orb/types/shared/new_plan_tiered_package_with_minimum_price.py new file mode 100644 index 00000000..eadcb1ba --- /dev/null +++ b/src/orb/types/shared/new_plan_tiered_package_with_minimum_price.py @@ -0,0 +1,131 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanTieredPackageWithMinimumPrice", + "TieredPackageWithMinimumConfig", + "TieredPackageWithMinimumConfigTier", + "ConversionRateConfig", +] + + +class TieredPackageWithMinimumConfigTier(BaseModel): + """Configuration for a single tier""" + + minimum_amount: str + + per_unit: str + + tier_lower_bound: str + + +class TieredPackageWithMinimumConfig(BaseModel): + """Configuration for tiered_package_with_minimum pricing""" + + package_size: float + + tiers: List[TieredPackageWithMinimumConfigTier] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. + """ + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanTieredPackageWithMinimumPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["tiered_package_with_minimum"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + tiered_package_with_minimum_config: TieredPackageWithMinimumConfig + """Configuration for tiered_package_with_minimum pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_tiered_price.py b/src/orb/types/shared/new_plan_tiered_price.py new file mode 100644 index 00000000..432552a2 --- /dev/null +++ b/src/orb/types/shared/new_plan_tiered_price.py @@ -0,0 +1,104 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .tiered_config import TieredConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanTieredPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanTieredPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["tiered"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + tiered_config: TieredConfig + """Configuration for tiered pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_tiered_with_minimum_price.py b/src/orb/types/shared/new_plan_tiered_with_minimum_price.py new file mode 100644 index 00000000..85db8e12 --- /dev/null +++ b/src/orb/types/shared/new_plan_tiered_with_minimum_price.py @@ -0,0 +1,136 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanTieredWithMinimumPrice", + "TieredWithMinimumConfig", + "TieredWithMinimumConfigTier", + "ConversionRateConfig", +] + + +class TieredWithMinimumConfigTier(BaseModel): + """Configuration for a single tier""" + + minimum_amount: str + + tier_lower_bound: str + + unit_amount: str + """Per unit amount""" + + +class TieredWithMinimumConfig(BaseModel): + """Configuration for tiered_with_minimum pricing""" + + tiers: List[TieredWithMinimumConfigTier] + """Tiered pricing with a minimum amount dependent on the volume tier. + + Tiers are defined using exclusive lower bounds. + """ + + hide_zero_amount_tiers: Optional[bool] = None + """If true, tiers with an accrued amount of 0 will not be included in the rating.""" + + prorate: Optional[bool] = None + """If true, the unit price will be prorated to the billing period""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanTieredWithMinimumPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["tiered_with_minimum"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + tiered_with_minimum_config: TieredWithMinimumConfig + """Configuration for tiered_with_minimum pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_unit_price.py b/src/orb/types/shared/new_plan_unit_price.py new file mode 100644 index 00000000..6eb148d5 --- /dev/null +++ b/src/orb/types/shared/new_plan_unit_price.py @@ -0,0 +1,104 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_config import UnitConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanUnitPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanUnitPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["unit"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + unit_config: UnitConfig + """Configuration for unit pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_unit_with_percent_price.py b/src/orb/types/shared/new_plan_unit_with_percent_price.py new file mode 100644 index 00000000..6e58e90b --- /dev/null +++ b/src/orb/types/shared/new_plan_unit_with_percent_price.py @@ -0,0 +1,114 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanUnitWithPercentPrice", "UnitWithPercentConfig", "ConversionRateConfig"] + + +class UnitWithPercentConfig(BaseModel): + """Configuration for unit_with_percent pricing""" + + percent: str + """What percent, out of 100, of the calculated total to charge""" + + unit_amount: str + """Rate per unit of usage""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanUnitWithPercentPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["unit_with_percent"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + unit_with_percent_config: UnitWithPercentConfig + """Configuration for unit_with_percent pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_plan_unit_with_proration_price.py b/src/orb/types/shared/new_plan_unit_with_proration_price.py new file mode 100644 index 00000000..9afdc036 --- /dev/null +++ b/src/orb/types/shared/new_plan_unit_with_proration_price.py @@ -0,0 +1,111 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanUnitWithProrationPrice", "UnitWithProrationConfig", "ConversionRateConfig"] + + +class UnitWithProrationConfig(BaseModel): + """Configuration for unit_with_proration pricing""" + + unit_amount: str + """Rate per unit of usage""" + + +ConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class NewPlanUnitWithProrationPrice(BaseModel): + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"] + """The cadence to bill for this price on.""" + + item_id: str + """The id of the item the price will be associated with.""" + + price_model_type: Literal["unit_with_proration"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + """The name of the price.""" + + unit_with_proration_config: UnitWithProrationConfig + """Configuration for unit_with_proration pricing""" + + billable_metric_id: Optional[str] = None + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] = None + """ + 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[NewBillingCycleConfiguration] = None + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] = None + """The per unit conversion rate of the price currency to the invoicing currency.""" + + conversion_rate_config: Optional[ConversionRateConfig] = None + """The configuration for the rate of the price currency to the invoicing currency.""" + + currency: Optional[str] = None + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] = None + """For dimensional price: specifies a price group and dimension values""" + + external_price_id: Optional[str] = None + """An alias for the price.""" + + fixed_price_quantity: Optional[float] = None + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] = None + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] = None + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] = None + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] = None + """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] = None + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ diff --git a/src/orb/types/shared/new_usage_discount.py b/src/orb/types/shared/new_usage_discount.py new file mode 100644 index 00000000..986cf09e --- /dev/null +++ b/src/orb/types/shared/new_usage_discount.py @@ -0,0 +1,49 @@ +# 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__ = ["NewUsageDiscount", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class NewUsageDiscount(BaseModel): + adjustment_type: Literal["usage_discount"] + + usage_discount: float + + applies_to_all: Optional[Literal[True]] = None + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[List[str]] = None + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[List[str]] = None + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] = None + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[List[Filter]] = None + """A list of filters that determine which prices this adjustment will apply to.""" + + is_invoice_level: Optional[bool] = None + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] = None + """If set, only prices of the specified type will have the adjustment applied.""" diff --git a/src/orb/types/shared/other_sub_line_item.py b/src/orb/types/shared/other_sub_line_item.py new file mode 100644 index 00000000..b8640ef3 --- /dev/null +++ b/src/orb/types/shared/other_sub_line_item.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .sub_line_item_grouping import SubLineItemGrouping + +__all__ = ["OtherSubLineItem"] + + +class OtherSubLineItem(BaseModel): + amount: str + """The total amount for this sub line item.""" + + grouping: Optional[SubLineItemGrouping] = None + + name: str + + quantity: float + + type: Literal["'null'"] diff --git a/src/orb/types/shared/package_config.py b/src/orb/types/shared/package_config.py new file mode 100644 index 00000000..fc4f1001 --- /dev/null +++ b/src/orb/types/shared/package_config.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["PackageConfig"] + + +class PackageConfig(BaseModel): + """Configuration for package pricing""" + + package_amount: str + """A currency amount to rate usage by""" + + package_size: int + """An integer amount to represent package size. + + For example, 1000 here would divide usage by 1000 before multiplying by + package_amount in rating + """ diff --git a/src/orb/types/shared/pagination_metadata.py b/src/orb/types/shared/pagination_metadata.py new file mode 100644 index 00000000..8390ceb5 --- /dev/null +++ b/src/orb/types/shared/pagination_metadata.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["PaginationMetadata"] + + +class PaginationMetadata(BaseModel): + has_more: bool + + next_cursor: Optional[str] = None diff --git a/src/orb/types/shared/per_price_cost.py b/src/orb/types/shared/per_price_cost.py new file mode 100644 index 00000000..3102fffd --- /dev/null +++ b/src/orb/types/shared/per_price_cost.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .price import Price +from ..._models import BaseModel + +__all__ = ["PerPriceCost"] + + +class PerPriceCost(BaseModel): + price: Price + """The price object""" + + price_id: str + """The price the cost is associated with""" + + subtotal: str + """Price's contributions for the timeframe, excluding any minimums and discounts.""" + + total: str + """Price's contributions for the timeframe, including minimums and discounts.""" + + quantity: Optional[float] = None + """The price's quantity for the timeframe""" diff --git a/src/orb/types/shared/percentage_discount.py b/src/orb/types/shared/percentage_discount.py new file mode 100644 index 00000000..3fb86bb5 --- /dev/null +++ b/src/orb/types/shared/percentage_discount.py @@ -0,0 +1,40 @@ +# 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", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class PercentageDiscount(BaseModel): + discount_type: Literal["percentage"] + + percentage_discount: float + """Only available if discount_type is `percentage`. + + This is a number between 0 and 1. + """ + + applies_to_price_ids: Optional[List[str]] = None + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + filters: Optional[List[Filter]] = None + """The filters that determine which prices to apply this discount to.""" + + reason: Optional[str] = None diff --git a/src/orb/types/shared/percentage_discount_interval.py b/src/orb/types/shared/percentage_discount_interval.py new file mode 100644 index 00000000..8b3b559c --- /dev/null +++ b/src/orb/types/shared/percentage_discount_interval.py @@ -0,0 +1,42 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["PercentageDiscountInterval", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class PercentageDiscountInterval(BaseModel): + 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.""" + + filters: List[Filter] + """The filters that determine which prices this discount interval applies to.""" + + 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.""" diff --git a/src/orb/types/shared/plan_phase_amount_discount_adjustment.py b/src/orb/types/shared/plan_phase_amount_discount_adjustment.py new file mode 100644 index 00000000..0aff9f2b --- /dev/null +++ b/src/orb/types/shared/plan_phase_amount_discount_adjustment.py @@ -0,0 +1,56 @@ +# 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__ = ["PlanPhaseAmountDiscountAdjustment", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class PlanPhaseAmountDiscountAdjustment(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.""" + + filters: List[Filter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, 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.""" + + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. + + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ diff --git a/src/orb/types/shared/plan_phase_maximum_adjustment.py b/src/orb/types/shared/plan_phase_maximum_adjustment.py new file mode 100644 index 00000000..f86df6d2 --- /dev/null +++ b/src/orb/types/shared/plan_phase_maximum_adjustment.py @@ -0,0 +1,56 @@ +# 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__ = ["PlanPhaseMaximumAdjustment", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class PlanPhaseMaximumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["maximum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + filters: List[Filter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, 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.""" + + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. + + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ diff --git a/src/orb/types/shared/plan_phase_minimum_adjustment.py b/src/orb/types/shared/plan_phase_minimum_adjustment.py new file mode 100644 index 00000000..a360bf4d --- /dev/null +++ b/src/orb/types/shared/plan_phase_minimum_adjustment.py @@ -0,0 +1,59 @@ +# 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__ = ["PlanPhaseMinimumAdjustment", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class PlanPhaseMinimumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["minimum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + filters: List[Filter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, 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.""" + + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. + + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ diff --git a/src/orb/types/shared/plan_phase_percentage_discount_adjustment.py b/src/orb/types/shared/plan_phase_percentage_discount_adjustment.py new file mode 100644 index 00000000..78f3119d --- /dev/null +++ b/src/orb/types/shared/plan_phase_percentage_discount_adjustment.py @@ -0,0 +1,56 @@ +# 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__ = ["PlanPhasePercentageDiscountAdjustment", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class PlanPhasePercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["percentage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + filters: List[Filter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, 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.""" + + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. + + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ diff --git a/src/orb/types/shared/plan_phase_usage_discount_adjustment.py b/src/orb/types/shared/plan_phase_usage_discount_adjustment.py new file mode 100644 index 00000000..a4691305 --- /dev/null +++ b/src/orb/types/shared/plan_phase_usage_discount_adjustment.py @@ -0,0 +1,56 @@ +# 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__ = ["PlanPhaseUsageDiscountAdjustment", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class PlanPhaseUsageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["usage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + filters: List[Filter] + """The filters that determine which prices to apply this adjustment to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invoice, 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.""" + + replaces_adjustment_id: Optional[str] = None + """The adjustment id this adjustment replaces. + + This adjustment will take the place of the replaced adjustment in plan version + migrations. + """ + + usage_discount: float + """ + The number of usage units by which to discount the price this adjustment applies + to in a given billing period. + """ diff --git a/src/orb/types/shared/price.py b/src/orb/types/shared/price.py new file mode 100644 index 00000000..c59b15e1 --- /dev/null +++ b/src/orb/types/shared/price.py @@ -0,0 +1,4917 @@ +# 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 pydantic import Field as FieldInfo + +from .maximum import Maximum +from .minimum import Minimum +from ..._utils import PropertyInfo +from .discount import Discount +from ..._models import BaseModel +from .item_slim import ItemSlim +from .allocation import Allocation +from .bulk_config import BulkConfig +from .unit_config import UnitConfig +from .matrix_config import MatrixConfig +from .tiered_config import TieredConfig +from .package_config import PackageConfig +from .billable_metric_tiny import BillableMetricTiny +from .billing_cycle_configuration import BillingCycleConfiguration +from .unit_conversion_rate_config import UnitConversionRateConfig +from .matrix_with_allocation_config import MatrixWithAllocationConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .dimensional_price_configuration import DimensionalPriceConfiguration + +__all__ = [ + "Price", + "UnitPrice", + "UnitPriceCompositePriceFilter", + "UnitPriceConversionRateConfig", + "UnitPriceLicenseType", + "TieredPrice", + "TieredPriceCompositePriceFilter", + "TieredPriceConversionRateConfig", + "TieredPriceLicenseType", + "BulkPrice", + "BulkPriceCompositePriceFilter", + "BulkPriceConversionRateConfig", + "BulkPriceLicenseType", + "BulkWithFiltersPrice", + "BulkWithFiltersPriceBulkWithFiltersConfig", + "BulkWithFiltersPriceBulkWithFiltersConfigFilter", + "BulkWithFiltersPriceBulkWithFiltersConfigTier", + "BulkWithFiltersPriceCompositePriceFilter", + "BulkWithFiltersPriceConversionRateConfig", + "BulkWithFiltersPriceLicenseType", + "PackagePrice", + "PackagePriceCompositePriceFilter", + "PackagePriceConversionRateConfig", + "PackagePriceLicenseType", + "MatrixPrice", + "MatrixPriceCompositePriceFilter", + "MatrixPriceConversionRateConfig", + "MatrixPriceLicenseType", + "ThresholdTotalAmountPrice", + "ThresholdTotalAmountPriceCompositePriceFilter", + "ThresholdTotalAmountPriceConversionRateConfig", + "ThresholdTotalAmountPriceThresholdTotalAmountConfig", + "ThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable", + "ThresholdTotalAmountPriceLicenseType", + "TieredPackagePrice", + "TieredPackagePriceCompositePriceFilter", + "TieredPackagePriceConversionRateConfig", + "TieredPackagePriceTieredPackageConfig", + "TieredPackagePriceTieredPackageConfigTier", + "TieredPackagePriceLicenseType", + "TieredWithMinimumPrice", + "TieredWithMinimumPriceCompositePriceFilter", + "TieredWithMinimumPriceConversionRateConfig", + "TieredWithMinimumPriceTieredWithMinimumConfig", + "TieredWithMinimumPriceTieredWithMinimumConfigTier", + "TieredWithMinimumPriceLicenseType", + "GroupedTieredPrice", + "GroupedTieredPriceCompositePriceFilter", + "GroupedTieredPriceConversionRateConfig", + "GroupedTieredPriceGroupedTieredConfig", + "GroupedTieredPriceGroupedTieredConfigTier", + "GroupedTieredPriceLicenseType", + "TieredPackageWithMinimumPrice", + "TieredPackageWithMinimumPriceCompositePriceFilter", + "TieredPackageWithMinimumPriceConversionRateConfig", + "TieredPackageWithMinimumPriceTieredPackageWithMinimumConfig", + "TieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier", + "TieredPackageWithMinimumPriceLicenseType", + "PackageWithAllocationPrice", + "PackageWithAllocationPriceCompositePriceFilter", + "PackageWithAllocationPriceConversionRateConfig", + "PackageWithAllocationPricePackageWithAllocationConfig", + "PackageWithAllocationPriceLicenseType", + "UnitWithPercentPrice", + "UnitWithPercentPriceCompositePriceFilter", + "UnitWithPercentPriceConversionRateConfig", + "UnitWithPercentPriceUnitWithPercentConfig", + "UnitWithPercentPriceLicenseType", + "MatrixWithAllocationPrice", + "MatrixWithAllocationPriceCompositePriceFilter", + "MatrixWithAllocationPriceConversionRateConfig", + "MatrixWithAllocationPriceLicenseType", + "MatrixWithThresholdDiscountsPrice", + "MatrixWithThresholdDiscountsPriceCompositePriceFilter", + "MatrixWithThresholdDiscountsPriceConversionRateConfig", + "MatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig", + "MatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue", + "MatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup", + "MatrixWithThresholdDiscountsPriceLicenseType", + "TieredWithProrationPrice", + "TieredWithProrationPriceCompositePriceFilter", + "TieredWithProrationPriceConversionRateConfig", + "TieredWithProrationPriceTieredWithProrationConfig", + "TieredWithProrationPriceTieredWithProrationConfigTier", + "TieredWithProrationPriceLicenseType", + "UnitWithProrationPrice", + "UnitWithProrationPriceCompositePriceFilter", + "UnitWithProrationPriceConversionRateConfig", + "UnitWithProrationPriceUnitWithProrationConfig", + "UnitWithProrationPriceLicenseType", + "GroupedAllocationPrice", + "GroupedAllocationPriceCompositePriceFilter", + "GroupedAllocationPriceConversionRateConfig", + "GroupedAllocationPriceGroupedAllocationConfig", + "GroupedAllocationPriceLicenseType", + "BulkWithProrationPrice", + "BulkWithProrationPriceBulkWithProrationConfig", + "BulkWithProrationPriceBulkWithProrationConfigTier", + "BulkWithProrationPriceCompositePriceFilter", + "BulkWithProrationPriceConversionRateConfig", + "BulkWithProrationPriceLicenseType", + "GroupedWithProratedMinimumPrice", + "GroupedWithProratedMinimumPriceCompositePriceFilter", + "GroupedWithProratedMinimumPriceConversionRateConfig", + "GroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig", + "GroupedWithProratedMinimumPriceLicenseType", + "GroupedWithMeteredMinimumPrice", + "GroupedWithMeteredMinimumPriceCompositePriceFilter", + "GroupedWithMeteredMinimumPriceConversionRateConfig", + "GroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig", + "GroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor", + "GroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount", + "GroupedWithMeteredMinimumPriceLicenseType", + "GroupedWithMinMaxThresholdsPrice", + "GroupedWithMinMaxThresholdsPriceCompositePriceFilter", + "GroupedWithMinMaxThresholdsPriceConversionRateConfig", + "GroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig", + "GroupedWithMinMaxThresholdsPriceLicenseType", + "MatrixWithDisplayNamePrice", + "MatrixWithDisplayNamePriceCompositePriceFilter", + "MatrixWithDisplayNamePriceConversionRateConfig", + "MatrixWithDisplayNamePriceMatrixWithDisplayNameConfig", + "MatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount", + "MatrixWithDisplayNamePriceLicenseType", + "GroupedTieredPackagePrice", + "GroupedTieredPackagePriceCompositePriceFilter", + "GroupedTieredPackagePriceConversionRateConfig", + "GroupedTieredPackagePriceGroupedTieredPackageConfig", + "GroupedTieredPackagePriceGroupedTieredPackageConfigTier", + "GroupedTieredPackagePriceLicenseType", + "MaxGroupTieredPackagePrice", + "MaxGroupTieredPackagePriceCompositePriceFilter", + "MaxGroupTieredPackagePriceConversionRateConfig", + "MaxGroupTieredPackagePriceMaxGroupTieredPackageConfig", + "MaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier", + "MaxGroupTieredPackagePriceLicenseType", + "ScalableMatrixWithUnitPricingPrice", + "ScalableMatrixWithUnitPricingPriceCompositePriceFilter", + "ScalableMatrixWithUnitPricingPriceConversionRateConfig", + "ScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig", + "ScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor", + "ScalableMatrixWithUnitPricingPriceLicenseType", + "ScalableMatrixWithTieredPricingPrice", + "ScalableMatrixWithTieredPricingPriceCompositePriceFilter", + "ScalableMatrixWithTieredPricingPriceConversionRateConfig", + "ScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig", + "ScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor", + "ScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier", + "ScalableMatrixWithTieredPricingPriceLicenseType", + "CumulativeGroupedBulkPrice", + "CumulativeGroupedBulkPriceCompositePriceFilter", + "CumulativeGroupedBulkPriceConversionRateConfig", + "CumulativeGroupedBulkPriceCumulativeGroupedBulkConfig", + "CumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue", + "CumulativeGroupedBulkPriceLicenseType", + "CumulativeGroupedAllocationPrice", + "CumulativeGroupedAllocationPriceCompositePriceFilter", + "CumulativeGroupedAllocationPriceConversionRateConfig", + "CumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig", + "CumulativeGroupedAllocationPriceLicenseType", + "DailyCreditAllowancePrice", + "DailyCreditAllowancePriceCompositePriceFilter", + "DailyCreditAllowancePriceConversionRateConfig", + "DailyCreditAllowancePriceDailyCreditAllowanceConfig", + "DailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue", + "DailyCreditAllowancePriceLicenseType", + "MeteredAllowancePrice", + "MeteredAllowancePriceCompositePriceFilter", + "MeteredAllowancePriceConversionRateConfig", + "MeteredAllowancePriceMeteredAllowanceConfig", + "MeteredAllowancePriceLicenseType", + "MinimumCompositePrice", + "MinimumCompositePriceCompositePriceFilter", + "MinimumCompositePriceConversionRateConfig", + "MinimumCompositePriceMinimumCompositeConfig", + "MinimumCompositePriceLicenseType", + "PercentCompositePrice", + "PercentCompositePriceCompositePriceFilter", + "PercentCompositePriceConversionRateConfig", + "PercentCompositePricePercentConfig", + "PercentCompositePriceLicenseType", + "EventOutputPrice", + "EventOutputPriceCompositePriceFilter", + "EventOutputPriceConversionRateConfig", + "EventOutputPriceEventOutputConfig", + "EventOutputPriceLicenseType", +] + + +class UnitPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +UnitPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class UnitPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class UnitPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[UnitPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[UnitPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["unit"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + unit_config: UnitConfig + """Configuration for unit pricing""" + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[UnitPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class TieredPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +TieredPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class TieredPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class TieredPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[TieredPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[TieredPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["tiered"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + tiered_config: TieredConfig + """Configuration for tiered pricing""" + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[TieredPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class BulkPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +BulkPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class BulkPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class BulkPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + bulk_config: BulkConfig + """Configuration for bulk pricing""" + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[BulkPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[BulkPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["bulk"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[BulkPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class BulkWithFiltersPriceBulkWithFiltersConfigFilter(BaseModel): + """Configuration for a single property filter""" + + property_key: str + """Event property key to filter on""" + + property_value: str + """Event property value to match""" + + +class BulkWithFiltersPriceBulkWithFiltersConfigTier(BaseModel): + """Configuration for a single bulk pricing tier""" + + unit_amount: str + """Amount per unit""" + + tier_lower_bound: Optional[str] = None + """The lower bound for this tier""" + + +class BulkWithFiltersPriceBulkWithFiltersConfig(BaseModel): + """Configuration for bulk_with_filters pricing""" + + filters: List[BulkWithFiltersPriceBulkWithFiltersConfigFilter] + """Property filters to apply (all must match)""" + + tiers: List[BulkWithFiltersPriceBulkWithFiltersConfigTier] + """Bulk tiers for rating based on total usage volume""" + + +class BulkWithFiltersPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +BulkWithFiltersPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class BulkWithFiltersPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class BulkWithFiltersPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + bulk_with_filters_config: BulkWithFiltersPriceBulkWithFiltersConfig + """Configuration for bulk_with_filters pricing""" + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[BulkWithFiltersPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[BulkWithFiltersPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["bulk_with_filters"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[BulkWithFiltersPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class PackagePriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +PackagePriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class PackagePriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class PackagePrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[PackagePriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[PackagePriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["package"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + package_config: PackageConfig + """Configuration for package pricing""" + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[PackagePriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class MatrixPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +MatrixPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class MatrixPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class MatrixPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[MatrixPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[MatrixPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + matrix_config: MatrixConfig + """Configuration for matrix pricing""" + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["matrix"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[MatrixPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class ThresholdTotalAmountPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +ThresholdTotalAmountPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class ThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable(BaseModel): + """Configuration for a single threshold""" + + threshold: str + + total_amount: str + """Total amount for this threshold""" + + +class ThresholdTotalAmountPriceThresholdTotalAmountConfig(BaseModel): + """Configuration for threshold_total_amount pricing""" + + consumption_table: List[ThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable] + """ + When the quantity consumed passes a provided threshold, the configured total + will be charged + """ + + prorate: Optional[bool] = None + """If true, the unit price will be prorated to the billing period""" + + +class ThresholdTotalAmountPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class ThresholdTotalAmountPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[ThresholdTotalAmountPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[ThresholdTotalAmountPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["threshold_total_amount"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + threshold_total_amount_config: ThresholdTotalAmountPriceThresholdTotalAmountConfig + """Configuration for threshold_total_amount pricing""" + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[ThresholdTotalAmountPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class TieredPackagePriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +TieredPackagePriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class TieredPackagePriceTieredPackageConfigTier(BaseModel): + """Configuration for a single tier with business logic""" + + per_unit: str + """Price per package""" + + tier_lower_bound: str + + +class TieredPackagePriceTieredPackageConfig(BaseModel): + """Configuration for tiered_package pricing""" + + package_size: str + + tiers: List[TieredPackagePriceTieredPackageConfigTier] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. The tier bounds are defined + based on the total quantity rather than the number of packages, so they must be + multiples of the package size. + """ + + +class TieredPackagePriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class TieredPackagePrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[TieredPackagePriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[TieredPackagePriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["tiered_package"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + tiered_package_config: TieredPackagePriceTieredPackageConfig + """Configuration for tiered_package pricing""" + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[TieredPackagePriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class TieredWithMinimumPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +TieredWithMinimumPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class TieredWithMinimumPriceTieredWithMinimumConfigTier(BaseModel): + """Configuration for a single tier""" + + minimum_amount: str + + tier_lower_bound: str + + unit_amount: str + """Per unit amount""" + + +class TieredWithMinimumPriceTieredWithMinimumConfig(BaseModel): + """Configuration for tiered_with_minimum pricing""" + + tiers: List[TieredWithMinimumPriceTieredWithMinimumConfigTier] + """Tiered pricing with a minimum amount dependent on the volume tier. + + Tiers are defined using exclusive lower bounds. + """ + + hide_zero_amount_tiers: Optional[bool] = None + """If true, tiers with an accrued amount of 0 will not be included in the rating.""" + + prorate: Optional[bool] = None + """If true, the unit price will be prorated to the billing period""" + + +class TieredWithMinimumPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class TieredWithMinimumPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[TieredWithMinimumPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[TieredWithMinimumPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["tiered_with_minimum"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + tiered_with_minimum_config: TieredWithMinimumPriceTieredWithMinimumConfig + """Configuration for tiered_with_minimum pricing""" + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[TieredWithMinimumPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class GroupedTieredPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +GroupedTieredPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class GroupedTieredPriceGroupedTieredConfigTier(BaseModel): + """Configuration for a single tier""" + + tier_lower_bound: str + + unit_amount: str + """Per unit amount""" + + +class GroupedTieredPriceGroupedTieredConfig(BaseModel): + """Configuration for grouped_tiered pricing""" + + grouping_key: str + """The billable metric property used to group before tiering""" + + tiers: List[GroupedTieredPriceGroupedTieredConfigTier] + """ + Apply tiered pricing to each segment generated after grouping with the provided + key + """ + + +class GroupedTieredPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class GroupedTieredPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[GroupedTieredPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[GroupedTieredPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + grouped_tiered_config: GroupedTieredPriceGroupedTieredConfig + """Configuration for grouped_tiered pricing""" + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["grouped_tiered"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[GroupedTieredPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class TieredPackageWithMinimumPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +TieredPackageWithMinimumPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class TieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier(BaseModel): + """Configuration for a single tier""" + + minimum_amount: str + + per_unit: str + + tier_lower_bound: str + + +class TieredPackageWithMinimumPriceTieredPackageWithMinimumConfig(BaseModel): + """Configuration for tiered_package_with_minimum pricing""" + + package_size: float + + tiers: List[TieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. + """ + + +class TieredPackageWithMinimumPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class TieredPackageWithMinimumPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[TieredPackageWithMinimumPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[TieredPackageWithMinimumPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["tiered_package_with_minimum"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + tiered_package_with_minimum_config: TieredPackageWithMinimumPriceTieredPackageWithMinimumConfig + """Configuration for tiered_package_with_minimum pricing""" + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[TieredPackageWithMinimumPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class PackageWithAllocationPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +PackageWithAllocationPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class PackageWithAllocationPricePackageWithAllocationConfig(BaseModel): + """Configuration for package_with_allocation pricing""" + + allocation: str + + package_amount: str + + package_size: str + + +class PackageWithAllocationPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class PackageWithAllocationPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[PackageWithAllocationPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[PackageWithAllocationPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["package_with_allocation"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + package_with_allocation_config: PackageWithAllocationPricePackageWithAllocationConfig + """Configuration for package_with_allocation pricing""" + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[PackageWithAllocationPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class UnitWithPercentPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +UnitWithPercentPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class UnitWithPercentPriceUnitWithPercentConfig(BaseModel): + """Configuration for unit_with_percent pricing""" + + percent: str + """What percent, out of 100, of the calculated total to charge""" + + unit_amount: str + """Rate per unit of usage""" + + +class UnitWithPercentPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class UnitWithPercentPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[UnitWithPercentPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[UnitWithPercentPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["unit_with_percent"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + unit_with_percent_config: UnitWithPercentPriceUnitWithPercentConfig + """Configuration for unit_with_percent pricing""" + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[UnitWithPercentPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class MatrixWithAllocationPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +MatrixWithAllocationPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class MatrixWithAllocationPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class MatrixWithAllocationPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[MatrixWithAllocationPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[MatrixWithAllocationPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + matrix_with_allocation_config: MatrixWithAllocationConfig + """Configuration for matrix_with_allocation pricing""" + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["matrix_with_allocation"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[MatrixWithAllocationPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class MatrixWithThresholdDiscountsPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +MatrixWithThresholdDiscountsPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class MatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue(BaseModel): + first_dimension_value: str + + unit_amount: str + + second_dimension_value: Optional[str] = None + + +class MatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup(BaseModel): + above_threshold_discount_percentage: str + """Discount rate applied to spend above the threshold.""" + + below_threshold_discount_percentage: str + """Discount rate applied to spend at or below the threshold. + + Set to 0 for no baseline discount. + """ + + cell_coordinates: str + """Semicolon-separated list of matrix cell coordinates targeted by this group. + + Each coordinate is `first,second` when the matrix has two dimensions, or just + `first` for a single-dimension matrix. Example: `blue,circle;green,triangle`. + """ + + threshold_amount: str + + description: Optional[str] = None + + +class MatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig(BaseModel): + """Configuration for matrix_with_threshold_discounts pricing""" + + default_unit_amount: str + """Unit price used for usage that does not match any defined matrix cell.""" + + first_dimension: str + """First matrix dimension key.""" + + matrix_values: List[MatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue] + """Per-cell unit prices.""" + + second_dimension: Optional[str] = None + """Optional second matrix dimension key.""" + + threshold_discount_groups: Optional[ + List[MatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup] + ] = None + + +class MatrixWithThresholdDiscountsPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class MatrixWithThresholdDiscountsPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[MatrixWithThresholdDiscountsPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[MatrixWithThresholdDiscountsPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + matrix_with_threshold_discounts_config: MatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + """Configuration for matrix_with_threshold_discounts pricing""" + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["matrix_with_threshold_discounts"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[MatrixWithThresholdDiscountsPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class TieredWithProrationPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +TieredWithProrationPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class TieredWithProrationPriceTieredWithProrationConfigTier(BaseModel): + """Configuration for a single tiered with proration tier""" + + tier_lower_bound: str + """Inclusive tier starting value""" + + unit_amount: str + """Amount per unit""" + + +class TieredWithProrationPriceTieredWithProrationConfig(BaseModel): + """Configuration for tiered_with_proration pricing""" + + tiers: List[TieredWithProrationPriceTieredWithProrationConfigTier] + """ + Tiers for rating based on total usage quantities into the specified tier with + proration + """ + + +class TieredWithProrationPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class TieredWithProrationPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[TieredWithProrationPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[TieredWithProrationPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["tiered_with_proration"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + tiered_with_proration_config: TieredWithProrationPriceTieredWithProrationConfig + """Configuration for tiered_with_proration pricing""" + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[TieredWithProrationPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class UnitWithProrationPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +UnitWithProrationPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class UnitWithProrationPriceUnitWithProrationConfig(BaseModel): + """Configuration for unit_with_proration pricing""" + + unit_amount: str + """Rate per unit of usage""" + + +class UnitWithProrationPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class UnitWithProrationPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[UnitWithProrationPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[UnitWithProrationPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["unit_with_proration"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + unit_with_proration_config: UnitWithProrationPriceUnitWithProrationConfig + """Configuration for unit_with_proration pricing""" + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[UnitWithProrationPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class GroupedAllocationPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +GroupedAllocationPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class GroupedAllocationPriceGroupedAllocationConfig(BaseModel): + """Configuration for grouped_allocation pricing""" + + allocation: str + """Usage allocation per group""" + + grouping_key: str + """How to determine the groups that should each be allocated some quantity""" + + overage_unit_rate: str + """Unit rate for post-allocation""" + + +class GroupedAllocationPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class GroupedAllocationPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[GroupedAllocationPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[GroupedAllocationPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + grouped_allocation_config: GroupedAllocationPriceGroupedAllocationConfig + """Configuration for grouped_allocation pricing""" + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["grouped_allocation"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[GroupedAllocationPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class BulkWithProrationPriceBulkWithProrationConfigTier(BaseModel): + """Configuration for a single bulk pricing tier with proration""" + + unit_amount: str + """Cost per unit""" + + tier_lower_bound: Optional[str] = None + """The lower bound for this tier""" + + +class BulkWithProrationPriceBulkWithProrationConfig(BaseModel): + """Configuration for bulk_with_proration pricing""" + + tiers: List[BulkWithProrationPriceBulkWithProrationConfigTier] + """Bulk tiers for rating based on total usage volume""" + + +class BulkWithProrationPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +BulkWithProrationPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class BulkWithProrationPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class BulkWithProrationPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + bulk_with_proration_config: BulkWithProrationPriceBulkWithProrationConfig + """Configuration for bulk_with_proration pricing""" + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[BulkWithProrationPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[BulkWithProrationPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["bulk_with_proration"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[BulkWithProrationPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class GroupedWithProratedMinimumPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +GroupedWithProratedMinimumPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class GroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig(BaseModel): + """Configuration for grouped_with_prorated_minimum pricing""" + + grouping_key: str + """How to determine the groups that should each have a minimum""" + + minimum: str + """The minimum amount to charge per group""" + + unit_rate: str + """The amount to charge per unit""" + + +class GroupedWithProratedMinimumPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class GroupedWithProratedMinimumPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[GroupedWithProratedMinimumPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[GroupedWithProratedMinimumPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + grouped_with_prorated_minimum_config: GroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig + """Configuration for grouped_with_prorated_minimum pricing""" + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["grouped_with_prorated_minimum"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[GroupedWithProratedMinimumPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class GroupedWithMeteredMinimumPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +GroupedWithMeteredMinimumPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class GroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor(BaseModel): + """Configuration for a scaling factor""" + + scaling_factor: str + + scaling_value: str + + +class GroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount(BaseModel): + """Configuration for a unit amount""" + + pricing_value: str + + unit_amount: str + """Per unit amount""" + + +class GroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig(BaseModel): + """Configuration for grouped_with_metered_minimum pricing""" + + grouping_key: str + """Used to partition the usage into groups. + + The minimum amount is applied to each group. + """ + + minimum_unit_amount: str + """The minimum amount to charge per group per unit""" + + pricing_key: str + """Used to determine the unit rate""" + + scaling_factors: List[GroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor] + """Scale the unit rates by the scaling factor.""" + + scaling_key: str + """Used to determine the unit rate scaling factor""" + + unit_amounts: List[GroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount] + """Apply per unit pricing to each pricing value. + + The minimum amount is applied any unmatched usage. + """ + + +class GroupedWithMeteredMinimumPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class GroupedWithMeteredMinimumPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[GroupedWithMeteredMinimumPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[GroupedWithMeteredMinimumPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + grouped_with_metered_minimum_config: GroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig + """Configuration for grouped_with_metered_minimum pricing""" + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["grouped_with_metered_minimum"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[GroupedWithMeteredMinimumPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class GroupedWithMinMaxThresholdsPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +GroupedWithMinMaxThresholdsPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class GroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig(BaseModel): + """Configuration for grouped_with_min_max_thresholds pricing""" + + grouping_key: str + """The event property used to group before applying thresholds""" + + maximum_charge: str + """The maximum amount to charge each group""" + + minimum_charge: str + """The minimum amount to charge each group, regardless of usage""" + + per_unit_rate: str + """The base price charged per group""" + + +class GroupedWithMinMaxThresholdsPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class GroupedWithMinMaxThresholdsPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[GroupedWithMinMaxThresholdsPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[GroupedWithMinMaxThresholdsPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + grouped_with_min_max_thresholds_config: GroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + """Configuration for grouped_with_min_max_thresholds pricing""" + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["grouped_with_min_max_thresholds"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[GroupedWithMinMaxThresholdsPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class MatrixWithDisplayNamePriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +MatrixWithDisplayNamePriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class MatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount(BaseModel): + """Configuration for a unit amount item""" + + dimension_value: str + """The dimension value""" + + display_name: str + """Display name for this dimension value""" + + unit_amount: str + """Per unit amount""" + + +class MatrixWithDisplayNamePriceMatrixWithDisplayNameConfig(BaseModel): + """Configuration for matrix_with_display_name pricing""" + + dimension: str + """Used to determine the unit rate""" + + unit_amounts: List[MatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount] + """Apply per unit pricing to each dimension value""" + + +class MatrixWithDisplayNamePriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class MatrixWithDisplayNamePrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[MatrixWithDisplayNamePriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[MatrixWithDisplayNamePriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + matrix_with_display_name_config: MatrixWithDisplayNamePriceMatrixWithDisplayNameConfig + """Configuration for matrix_with_display_name pricing""" + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["matrix_with_display_name"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[MatrixWithDisplayNamePriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class GroupedTieredPackagePriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +GroupedTieredPackagePriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class GroupedTieredPackagePriceGroupedTieredPackageConfigTier(BaseModel): + """Configuration for a single tier""" + + per_unit: str + """Per package""" + + tier_lower_bound: str + + +class GroupedTieredPackagePriceGroupedTieredPackageConfig(BaseModel): + """Configuration for grouped_tiered_package pricing""" + + grouping_key: str + """The event property used to group before tiering""" + + package_size: str + + tiers: List[GroupedTieredPackagePriceGroupedTieredPackageConfigTier] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. + """ + + +class GroupedTieredPackagePriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class GroupedTieredPackagePrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[GroupedTieredPackagePriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[GroupedTieredPackagePriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + grouped_tiered_package_config: GroupedTieredPackagePriceGroupedTieredPackageConfig + """Configuration for grouped_tiered_package pricing""" + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["grouped_tiered_package"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[GroupedTieredPackagePriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class MaxGroupTieredPackagePriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +MaxGroupTieredPackagePriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class MaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier(BaseModel): + """Configuration for a single tier""" + + tier_lower_bound: str + + unit_amount: str + """Per unit amount""" + + +class MaxGroupTieredPackagePriceMaxGroupTieredPackageConfig(BaseModel): + """Configuration for max_group_tiered_package pricing""" + + grouping_key: str + """ + The event property used to group before tiering the group with the highest value + """ + + package_size: str + + tiers: List[MaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier] + """Apply tiered pricing to the largest group after grouping with the provided key.""" + + +class MaxGroupTieredPackagePriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class MaxGroupTieredPackagePrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[MaxGroupTieredPackagePriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[MaxGroupTieredPackagePriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + max_group_tiered_package_config: MaxGroupTieredPackagePriceMaxGroupTieredPackageConfig + """Configuration for max_group_tiered_package pricing""" + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["max_group_tiered_package"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[MaxGroupTieredPackagePriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class ScalableMatrixWithUnitPricingPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +ScalableMatrixWithUnitPricingPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class ScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor(BaseModel): + """Configuration for a single matrix scaling factor""" + + first_dimension_value: str + + scaling_factor: str + + second_dimension_value: Optional[str] = None + + +class ScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig(BaseModel): + """Configuration for scalable_matrix_with_unit_pricing pricing""" + + first_dimension: str + """Used to determine the unit rate""" + + matrix_scaling_factors: List[ + ScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor + ] + """Apply a scaling factor to each dimension""" + + unit_price: str + """The final unit price to rate against the output of the matrix""" + + grouping_key: Optional[str] = None + """The property used to group this price""" + + prorate: Optional[bool] = None + """If true, the unit price will be prorated to the billing period""" + + second_dimension: Optional[str] = None + """Used to determine the unit rate (optional)""" + + +class ScalableMatrixWithUnitPricingPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class ScalableMatrixWithUnitPricingPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[ScalableMatrixWithUnitPricingPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[ScalableMatrixWithUnitPricingPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["scalable_matrix_with_unit_pricing"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + scalable_matrix_with_unit_pricing_config: ScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig + """Configuration for scalable_matrix_with_unit_pricing pricing""" + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[ScalableMatrixWithUnitPricingPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class ScalableMatrixWithTieredPricingPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +ScalableMatrixWithTieredPricingPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class ScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor(BaseModel): + """Configuration for a single matrix scaling factor""" + + first_dimension_value: str + + scaling_factor: str + + second_dimension_value: Optional[str] = None + + +class ScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier(BaseModel): + """Configuration for a single tier entry with business logic""" + + tier_lower_bound: str + + unit_amount: str + + +class ScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig(BaseModel): + """Configuration for scalable_matrix_with_tiered_pricing pricing""" + + first_dimension: str + """Used for the scalable matrix first dimension""" + + matrix_scaling_factors: List[ + ScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor + ] + """Apply a scaling factor to each dimension""" + + tiers: List[ScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier] + + second_dimension: Optional[str] = None + """Used for the scalable matrix second dimension (optional)""" + + +class ScalableMatrixWithTieredPricingPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class ScalableMatrixWithTieredPricingPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[ScalableMatrixWithTieredPricingPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[ScalableMatrixWithTieredPricingPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["scalable_matrix_with_tiered_pricing"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + scalable_matrix_with_tiered_pricing_config: ( + ScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig + ) + """Configuration for scalable_matrix_with_tiered_pricing pricing""" + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[ScalableMatrixWithTieredPricingPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class CumulativeGroupedBulkPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +CumulativeGroupedBulkPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class CumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue(BaseModel): + """Configuration for a dimension value entry""" + + grouping_key: str + """Grouping key value""" + + tier_lower_bound: str + """Tier lower bound""" + + unit_amount: str + """Unit amount for this combination""" + + +class CumulativeGroupedBulkPriceCumulativeGroupedBulkConfig(BaseModel): + """Configuration for cumulative_grouped_bulk pricing""" + + dimension_values: List[CumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue] + """Each tier lower bound must have the same group of values.""" + + group: str + + +class CumulativeGroupedBulkPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class CumulativeGroupedBulkPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[CumulativeGroupedBulkPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[CumulativeGroupedBulkPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + cumulative_grouped_bulk_config: CumulativeGroupedBulkPriceCumulativeGroupedBulkConfig + """Configuration for cumulative_grouped_bulk pricing""" + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["cumulative_grouped_bulk"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[CumulativeGroupedBulkPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class CumulativeGroupedAllocationPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +CumulativeGroupedAllocationPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class CumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig(BaseModel): + """Configuration for cumulative_grouped_allocation pricing""" + + cumulative_allocation: str + """The overall allocation across all groups""" + + group_allocation: str + """The allocation per individual group""" + + grouping_key: str + """The event property used to group usage before applying allocations""" + + unit_amount: str + """The amount to charge for each unit outside of the allocation""" + + +class CumulativeGroupedAllocationPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class CumulativeGroupedAllocationPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[CumulativeGroupedAllocationPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[CumulativeGroupedAllocationPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + cumulative_grouped_allocation_config: CumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + """Configuration for cumulative_grouped_allocation pricing""" + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["cumulative_grouped_allocation"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[CumulativeGroupedAllocationPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class DailyCreditAllowancePriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +DailyCreditAllowancePriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class DailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue(BaseModel): + """Per-dimension credit price for the daily credit allowance model.""" + + dimension_values: List[Optional[str]] + """One or two matrix keys to filter usage to this value by. + + For example, ["model"] could be used to apply a different credit rate to each AI + model. + """ + + unit_amount: str + """Credits charged per unit of usage matching the specified dimension_values""" + + +class DailyCreditAllowancePriceDailyCreditAllowanceConfig(BaseModel): + """Configuration for daily_credit_allowance pricing""" + + daily_allowance: str + """Credits granted per day. Lose-it-or-use-it; does not roll over.""" + + default_unit_amount: str + """ + Default per-unit credit rate for any usage not bucketed into a specified + matrix_value + """ + + dimensions: List[Optional[str]] + """One or two event property values to evaluate matrix groups by""" + + event_day_property: str + """Event property whose value identifies the day bucket the event belongs to (e.g. + + 'event_day' set to an ISO date string in the customer's timezone). The allowance + resets per distinct value of this property. + """ + + matrix_values: List[DailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue] + """Per-dimension credit rates""" + + +class DailyCreditAllowancePriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class DailyCreditAllowancePrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[DailyCreditAllowancePriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[DailyCreditAllowancePriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + daily_credit_allowance_config: DailyCreditAllowancePriceDailyCreditAllowanceConfig + """Configuration for daily_credit_allowance pricing""" + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["daily_credit_allowance"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[DailyCreditAllowancePriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class MeteredAllowancePriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +MeteredAllowancePriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class MeteredAllowancePriceMeteredAllowanceConfig(BaseModel): + """Configuration for metered_allowance pricing""" + + allowance_grouping_value: str + """ + The grouping_key value whose summed quantity represents the allowance for this + period (e.g. 'storage_snapshot' emitting 3 × avg storage). Capped at consumption + — credit can never exceed actual usage. + """ + + consumption_grouping_value: str + """The grouping_key value whose summed quantity represents consumption (e.g. + + 'download'). Charged at unit_amount. + """ + + grouping_key: str + """ + Event property used to partition the metric into consumption and allowance + quantities (e.g. 'event_name'). The metric is queried with this key and the two + values below select which partition is which. + """ + + unit_amount: str + """Per-unit price applied to gross consumption and to the allowance credit.""" + + allowance_display_name: Optional[str] = None + """Sub-line label for the credit row (e.g. 'Up to 3x free egress').""" + + consumption_display_name: Optional[str] = None + """Sub-line label for the gross consumption row (e.g. 'bytes gotten').""" + + +class MeteredAllowancePriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class MeteredAllowancePrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[MeteredAllowancePriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[MeteredAllowancePriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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`. + """ + + metered_allowance_config: MeteredAllowancePriceMeteredAllowanceConfig + """Configuration for metered_allowance pricing""" + + minimum: Optional[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["metered_allowance"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[MeteredAllowancePriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class MinimumCompositePriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +MinimumCompositePriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class MinimumCompositePriceMinimumCompositeConfig(BaseModel): + """Configuration for minimum_composite pricing""" + + minimum_amount: str + """The minimum amount to apply""" + + prorated: Optional[bool] = None + """If true, subtotals from this price are prorated based on the service period""" + + +class MinimumCompositePriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class MinimumCompositePrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[MinimumCompositePriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[MinimumCompositePriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + minimum_composite_config: MinimumCompositePriceMinimumCompositeConfig + """Configuration for minimum_composite pricing""" + + price_model_type: Literal["minimum_composite"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[MinimumCompositePriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class PercentCompositePriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +PercentCompositePriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class PercentCompositePricePercentConfig(BaseModel): + """Configuration for percent pricing""" + + percent: float + """Fraction of the component subtotals to charge (0 < percent <= 1).""" + + maximum_amount: Optional[str] = None + """Maximum amount to charge. If unset, the fee has no upper bound.""" + + minimum_amount: Optional[str] = None + """Minimum amount to charge. If unset, the fee is bounded below by 0.""" + + prorated: Optional[bool] = None + """If true, the minimum_amount is prorated based on the service period. + + The maximum_amount is an absolute cap (never prorated), and the percent applied + to upstream subtotals is never prorated either. + """ + + +class PercentCompositePriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class PercentCompositePrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[PercentCompositePriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[PercentCompositePriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["percent"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + percent_config: PercentCompositePricePercentConfig + """Configuration for percent pricing""" + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[PercentCompositePriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +class EventOutputPriceCompositePriceFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +EventOutputPriceConversionRateConfig: TypeAlias = Annotated[ + Union[UnitConversionRateConfig, TieredConversionRateConfig], PropertyInfo(discriminator="conversion_rate_type") +] + + +class EventOutputPriceEventOutputConfig(BaseModel): + """Configuration for event_output pricing""" + + unit_rating_key: str + """The key in the event data to extract the unit rate from.""" + + default_unit_rate: Optional[str] = None + """ + If provided, this amount will be used as the unit rate when an event does not + have a value for the `unit_rating_key`. If not provided, events missing a unit + rate will be ignored. + """ + + grouping_key: Optional[str] = None + """An optional key in the event data to group by (e.g., event ID). + + All events will also be grouped by their unit rate. + """ + + +class EventOutputPriceLicenseType(BaseModel): + """ + The LicenseType resource represents a type of license that can be assigned to users. + License types are used during billing by grouping metrics on the configured grouping key. + """ + + id: str + """The Orb-assigned unique identifier for the license type.""" + + grouping_key: str + """The key used for grouping licenses of this type. + + This is typically a user identifier field. + """ + + name: str + """The name of the license type.""" + + +class EventOutputPrice(BaseModel): + id: str + + billable_metric: Optional[BillableMetricTiny] = None + + billing_cycle_configuration: BillingCycleConfiguration + + billing_mode: Literal["in_advance", "in_arrear"] + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + composite_price_filters: Optional[List[EventOutputPriceCompositePriceFilter]] = None + + conversion_rate: Optional[float] = None + + conversion_rate_config: Optional[EventOutputPriceConversionRateConfig] = None + + created_at: datetime + + credit_allocation: Optional[Allocation] = None + + currency: str + + discount: Optional[Discount] = None + + event_output_config: EventOutputPriceEventOutputConfig + """Configuration for event_output pricing""" + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoice_grouping_key: Optional[str] = None + + invoicing_cycle_configuration: Optional[BillingCycleConfiguration] = None + + item: ItemSlim + """ + A minimal representation of an Item containing only the essential identifying + information. + """ + + maximum: Optional[Maximum] = 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[Minimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["event_output"] = FieldInfo(alias="model_type") + """The pricing model type""" + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price", "composite_price"] + + replaces_price_id: Optional[str] = None + """The price id this price replaces. + + This price will take the place of the replaced price in plan version migrations. + """ + + dimensional_price_configuration: Optional[DimensionalPriceConfiguration] = None + + license_type: Optional[EventOutputPriceLicenseType] = None + """ + The LicenseType resource represents a type of license that can be assigned to + users. License types are used during billing by grouping metrics on the + configured grouping key. + """ + + +Price: TypeAlias = Annotated[ + Union[ + UnitPrice, + TieredPrice, + BulkPrice, + BulkWithFiltersPrice, + PackagePrice, + MatrixPrice, + ThresholdTotalAmountPrice, + TieredPackagePrice, + TieredWithMinimumPrice, + GroupedTieredPrice, + TieredPackageWithMinimumPrice, + PackageWithAllocationPrice, + UnitWithPercentPrice, + MatrixWithAllocationPrice, + MatrixWithThresholdDiscountsPrice, + TieredWithProrationPrice, + UnitWithProrationPrice, + GroupedAllocationPrice, + BulkWithProrationPrice, + GroupedWithProratedMinimumPrice, + GroupedWithMeteredMinimumPrice, + GroupedWithMinMaxThresholdsPrice, + MatrixWithDisplayNamePrice, + GroupedTieredPackagePrice, + MaxGroupTieredPackagePrice, + ScalableMatrixWithUnitPricingPrice, + ScalableMatrixWithTieredPricingPrice, + CumulativeGroupedBulkPrice, + CumulativeGroupedAllocationPrice, + DailyCreditAllowancePrice, + MeteredAllowancePrice, + MinimumCompositePrice, + PercentCompositePrice, + EventOutputPrice, + ], + PropertyInfo(discriminator="price_model_type"), +] diff --git a/src/orb/types/shared/price_interval.py b/src/orb/types/shared/price_interval.py new file mode 100644 index 00000000..03fa50be --- /dev/null +++ b/src/orb/types/shared/price_interval.py @@ -0,0 +1,91 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from datetime import datetime + +from .price import Price +from ..._models import BaseModel +from .fixed_fee_quantity_transition import FixedFeeQuantityTransition + +__all__ = ["PriceInterval"] + + +class PriceInterval(BaseModel): + """ + The Price Interval resource represents a period of time for which a price will bill on a subscription. A + subscription’s price intervals define its billing behavior. + """ + + id: str + + billing_cycle_day: int + """The day of the month that Orb bills for this price""" + + can_defer_billing: bool + """For in-arrears prices. + + If true, and the price interval ends mid-cycle, the final line item will be + deferred to the next scheduled invoice instead of being billed mid-cycle. + """ + + 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. + """ + + filter: Optional[str] = None + """An additional filter to apply to usage queries.""" + + fixed_fee_quantity_transitions: Optional[List[FixedFeeQuantityTransition]] = 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. + + For more on the types of prices, see + [the core concepts documentation](/core-concepts#plan-and-price) + """ + + start_date: datetime + """The start date of the price interval. + + This is the date that Orb starts billing for this price. + """ + + usage_customer_ids: Optional[List[str]] = None + """ + A list of customer IDs whose usage events will be aggregated and billed under + this price interval. + """ + + metric_parameter_overrides: Optional[Dict[str, object]] = None + """Override values for parameterized billable metric variables. + + Keys are parameter names, values are the override values. + """ diff --git a/src/orb/types/shared/sub_line_item_grouping.py b/src/orb/types/shared/sub_line_item_grouping.py new file mode 100644 index 00000000..d4f06014 --- /dev/null +++ b/src/orb/types/shared/sub_line_item_grouping.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["SubLineItemGrouping"] + + +class SubLineItemGrouping(BaseModel): + key: str + + value: Optional[str] = None + """No value indicates the default group""" diff --git a/src/orb/types/shared/sub_line_item_matrix_config.py b/src/orb/types/shared/sub_line_item_matrix_config.py new file mode 100644 index 00000000..b0a11cd1 --- /dev/null +++ b/src/orb/types/shared/sub_line_item_matrix_config.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["SubLineItemMatrixConfig"] + + +class SubLineItemMatrixConfig(BaseModel): + dimension_values: List[Optional[str]] + """The ordered dimension values for this line item.""" diff --git a/src/orb/types/shared/subscription_change_minified.py b/src/orb/types/shared/subscription_change_minified.py new file mode 100644 index 00000000..1d9e2949 --- /dev/null +++ b/src/orb/types/shared/subscription_change_minified.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["SubscriptionChangeMinified"] + + +class SubscriptionChangeMinified(BaseModel): + id: str diff --git a/src/orb/types/shared/subscription_minified.py b/src/orb/types/shared/subscription_minified.py new file mode 100644 index 00000000..8f2ebde9 --- /dev/null +++ b/src/orb/types/shared/subscription_minified.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["SubscriptionMinified"] + + +class SubscriptionMinified(BaseModel): + id: str diff --git a/src/orb/types/shared/subscription_trial_info.py b/src/orb/types/shared/subscription_trial_info.py new file mode 100644 index 00000000..5a24174d --- /dev/null +++ b/src/orb/types/shared/subscription_trial_info.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["SubscriptionTrialInfo"] + + +class SubscriptionTrialInfo(BaseModel): + end_date: Optional[datetime] = None diff --git a/src/orb/types/shared/tax_amount.py b/src/orb/types/shared/tax_amount.py new file mode 100644 index 00000000..64e84f2b --- /dev/null +++ b/src/orb/types/shared/tax_amount.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["TaxAmount"] + + +class TaxAmount(BaseModel): + amount: str + """The amount of additional tax incurred by this tax rate.""" + + tax_rate_description: str + """The human-readable description of the applied tax rate.""" + + tax_rate_percentage: Optional[str] = None + """The tax rate percentage, out of 100.""" diff --git a/src/orb/types/shared/tier.py b/src/orb/types/shared/tier.py new file mode 100644 index 00000000..b17676a9 --- /dev/null +++ b/src/orb/types/shared/tier.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["Tier"] + + +class Tier(BaseModel): + """Configuration for a single tier""" + + first_unit: float + """Exclusive tier starting value""" + + unit_amount: str + """Amount per unit""" + + last_unit: Optional[float] = None + """Inclusive tier ending value. + + This value is null if and only if this is the last tier. + """ diff --git a/src/orb/types/shared/tier_sub_line_item.py b/src/orb/types/shared/tier_sub_line_item.py new file mode 100644 index 00000000..246a38ba --- /dev/null +++ b/src/orb/types/shared/tier_sub_line_item.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .sub_line_item_grouping import SubLineItemGrouping + +__all__ = ["TierSubLineItem", "TierConfig"] + + +class TierConfig(BaseModel): + first_unit: float + + last_unit: Optional[float] = None + + unit_amount: str + + +class TierSubLineItem(BaseModel): + amount: str + """The total amount for this sub line item.""" + + grouping: Optional[SubLineItemGrouping] = None + + name: str + + quantity: float + + tier_config: TierConfig + + type: Literal["tier"] diff --git a/src/orb/types/shared/tiered_config.py b/src/orb/types/shared/tiered_config.py new file mode 100644 index 00000000..ac4c2e46 --- /dev/null +++ b/src/orb/types/shared/tiered_config.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .tier import Tier +from ..._models import BaseModel + +__all__ = ["TieredConfig"] + + +class TieredConfig(BaseModel): + """Configuration for tiered pricing""" + + tiers: List[Tier] + """Tiers for rating based on total usage quantities into the specified tier""" + + prorated: Optional[bool] = None + """If true, subtotals from this price are prorated based on the service period""" diff --git a/src/orb/types/shared/tiered_conversion_rate_config.py b/src/orb/types/shared/tiered_conversion_rate_config.py new file mode 100644 index 00000000..5bbb9922 --- /dev/null +++ b/src/orb/types/shared/tiered_conversion_rate_config.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .conversion_rate_tiered_config import ConversionRateTieredConfig + +__all__ = ["TieredConversionRateConfig"] + + +class TieredConversionRateConfig(BaseModel): + conversion_rate_type: Literal["tiered"] + + tiered_config: ConversionRateTieredConfig diff --git a/src/orb/types/shared/trial_discount.py b/src/orb/types/shared/trial_discount.py new file mode 100644 index 00000000..a39fa8dd --- /dev/null +++ b/src/orb/types/shared/trial_discount.py @@ -0,0 +1,40 @@ +# 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", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class TrialDiscount(BaseModel): + discount_type: Literal["trial"] + + applies_to_price_ids: Optional[List[str]] = None + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + filters: Optional[List[Filter]] = None + """The filters that determine which prices to apply this discount to.""" + + 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/unit_config.py b/src/orb/types/shared/unit_config.py new file mode 100644 index 00000000..04fae258 --- /dev/null +++ b/src/orb/types/shared/unit_config.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["UnitConfig"] + + +class UnitConfig(BaseModel): + """Configuration for unit pricing""" + + unit_amount: str + """Rate per unit of usage""" + + prorated: Optional[bool] = None + """If true, subtotals from this price are prorated based on the service period""" diff --git a/src/orb/types/shared/unit_conversion_rate_config.py b/src/orb/types/shared/unit_conversion_rate_config.py new file mode 100644 index 00000000..184f1c75 --- /dev/null +++ b/src/orb/types/shared/unit_conversion_rate_config.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel +from .conversion_rate_unit_config import ConversionRateUnitConfig + +__all__ = ["UnitConversionRateConfig"] + + +class UnitConversionRateConfig(BaseModel): + conversion_rate_type: Literal["unit"] + + unit_config: ConversionRateUnitConfig diff --git a/src/orb/types/shared/usage_discount.py b/src/orb/types/shared/usage_discount.py new file mode 100644 index 00000000..34548a0e --- /dev/null +++ b/src/orb/types/shared/usage_discount.py @@ -0,0 +1,40 @@ +# 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__ = ["UsageDiscount", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class UsageDiscount(BaseModel): + discount_type: Literal["usage"] + + usage_discount: float + """Only available if discount_type is `usage`. + + Number of usage units that this discount is for + """ + + applies_to_price_ids: Optional[List[str]] = None + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + filters: Optional[List[Filter]] = None + """The filters that determine which prices to apply this discount to.""" + + reason: Optional[str] = None diff --git a/src/orb/types/shared/usage_discount_interval.py b/src/orb/types/shared/usage_discount_interval.py new file mode 100644 index 00000000..909b34dd --- /dev/null +++ b/src/orb/types/shared/usage_discount_interval.py @@ -0,0 +1,42 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["UsageDiscountInterval", "Filter"] + + +class Filter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" + + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" + + values: List[str] + """The IDs or values that match this filter.""" + + +class UsageDiscountInterval(BaseModel): + 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.""" + + filters: List[Filter] + """The filters that determine which prices this discount interval applies to.""" + + 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 + """ diff --git a/src/orb/types/shared_params/__init__.py b/src/orb/types/shared_params/__init__.py new file mode 100644 index 00000000..1e5dbc25 --- /dev/null +++ b/src/orb/types/shared_params/__init__.py @@ -0,0 +1,136 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .tier import Tier as Tier +from .discount import Discount as Discount +from .bulk_tier import BulkTier as BulkTier +from .bulk_config import BulkConfig as BulkConfig +from .new_maximum import NewMaximum as NewMaximum +from .new_minimum import NewMinimum as NewMinimum +from .unit_config import UnitConfig as UnitConfig +from .matrix_value import MatrixValue as MatrixValue +from .matrix_config import MatrixConfig as MatrixConfig +from .tiered_config import TieredConfig as TieredConfig +from .package_config import PackageConfig as PackageConfig +from .trial_discount import TrialDiscount as TrialDiscount +from .usage_discount import UsageDiscount as UsageDiscount +from .amount_discount import AmountDiscount as AmountDiscount +from .customer_tax_id import CustomerTaxID as CustomerTaxID +from .custom_expiration import CustomExpiration as CustomExpiration +from .new_usage_discount import NewUsageDiscount as NewUsageDiscount +from .new_amount_discount import NewAmountDiscount as NewAmountDiscount +from .new_plan_bulk_price import NewPlanBulkPrice as NewPlanBulkPrice +from .new_plan_unit_price import NewPlanUnitPrice as NewPlanUnitPrice +from .percentage_discount import PercentageDiscount as PercentageDiscount +from .conversion_rate_tier import ConversionRateTier as ConversionRateTier +from .new_allocation_price import NewAllocationPrice as NewAllocationPrice +from .new_plan_matrix_price import NewPlanMatrixPrice as NewPlanMatrixPrice +from .new_plan_tiered_price import NewPlanTieredPrice as NewPlanTieredPrice +from .new_plan_package_price import NewPlanPackagePrice as NewPlanPackagePrice +from .new_floating_bulk_price import NewFloatingBulkPrice as NewFloatingBulkPrice +from .new_floating_unit_price import NewFloatingUnitPrice as NewFloatingUnitPrice +from .new_percentage_discount import NewPercentageDiscount as NewPercentageDiscount +from .new_floating_matrix_price import NewFloatingMatrixPrice as NewFloatingMatrixPrice +from .new_floating_tiered_price import NewFloatingTieredPrice as NewFloatingTieredPrice +from .new_floating_package_price import NewFloatingPackagePrice as NewFloatingPackagePrice +from .billing_cycle_relative_date import BillingCycleRelativeDate as BillingCycleRelativeDate +from .conversion_rate_unit_config import ConversionRateUnitConfig as ConversionRateUnitConfig +from .unit_conversion_rate_config import UnitConversionRateConfig as UnitConversionRateConfig +from .conversion_rate_tiered_config import ConversionRateTieredConfig as ConversionRateTieredConfig +from .matrix_with_allocation_config import MatrixWithAllocationConfig as MatrixWithAllocationConfig +from .new_plan_grouped_tiered_price import NewPlanGroupedTieredPrice as NewPlanGroupedTieredPrice +from .new_plan_tiered_package_price import NewPlanTieredPackagePrice as NewPlanTieredPackagePrice +from .tiered_conversion_rate_config import TieredConversionRateConfig as TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration as NewBillingCycleConfiguration +from .new_plan_minimum_composite_price import NewPlanMinimumCompositePrice as NewPlanMinimumCompositePrice +from .new_plan_unit_with_percent_price import NewPlanUnitWithPercentPrice as NewPlanUnitWithPercentPrice +from .new_floating_grouped_tiered_price import NewFloatingGroupedTieredPrice as NewFloatingGroupedTieredPrice +from .new_floating_tiered_package_price import NewFloatingTieredPackagePrice as NewFloatingTieredPackagePrice +from .new_plan_grouped_allocation_price import NewPlanGroupedAllocationPrice as NewPlanGroupedAllocationPrice +from .billing_cycle_anchor_configuration import BillingCycleAnchorConfiguration as BillingCycleAnchorConfiguration +from .new_plan_bulk_with_proration_price import NewPlanBulkWithProrationPrice as NewPlanBulkWithProrationPrice +from .new_plan_tiered_with_minimum_price import NewPlanTieredWithMinimumPrice as NewPlanTieredWithMinimumPrice +from .new_plan_unit_with_proration_price import NewPlanUnitWithProrationPrice as NewPlanUnitWithProrationPrice +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration as NewDimensionalPriceConfiguration +from .new_floating_minimum_composite_price import NewFloatingMinimumCompositePrice as NewFloatingMinimumCompositePrice +from .new_floating_unit_with_percent_price import NewFloatingUnitWithPercentPrice as NewFloatingUnitWithPercentPrice +from .new_floating_grouped_allocation_price import ( + NewFloatingGroupedAllocationPrice as NewFloatingGroupedAllocationPrice, +) +from .new_plan_grouped_tiered_package_price import NewPlanGroupedTieredPackagePrice as NewPlanGroupedTieredPackagePrice +from .new_plan_matrix_with_allocation_price import NewPlanMatrixWithAllocationPrice as NewPlanMatrixWithAllocationPrice +from .new_plan_threshold_total_amount_price import NewPlanThresholdTotalAmountPrice as NewPlanThresholdTotalAmountPrice +from .new_floating_bulk_with_proration_price import ( + NewFloatingBulkWithProrationPrice as NewFloatingBulkWithProrationPrice, +) +from .new_floating_tiered_with_minimum_price import ( + NewFloatingTieredWithMinimumPrice as NewFloatingTieredWithMinimumPrice, +) +from .new_floating_unit_with_proration_price import ( + NewFloatingUnitWithProrationPrice as NewFloatingUnitWithProrationPrice, +) +from .new_plan_cumulative_grouped_bulk_price import ( + NewPlanCumulativeGroupedBulkPrice as NewPlanCumulativeGroupedBulkPrice, +) +from .new_plan_package_with_allocation_price import ( + NewPlanPackageWithAllocationPrice as NewPlanPackageWithAllocationPrice, +) +from .new_plan_matrix_with_display_name_price import ( + NewPlanMatrixWithDisplayNamePrice as NewPlanMatrixWithDisplayNamePrice, +) +from .new_plan_max_group_tiered_package_price import ( + NewPlanMaxGroupTieredPackagePrice as NewPlanMaxGroupTieredPackagePrice, +) +from .new_floating_tiered_with_proration_price import ( + NewFloatingTieredWithProrationPrice as NewFloatingTieredWithProrationPrice, +) +from .new_floating_grouped_tiered_package_price import ( + NewFloatingGroupedTieredPackagePrice as NewFloatingGroupedTieredPackagePrice, +) +from .new_floating_matrix_with_allocation_price import ( + NewFloatingMatrixWithAllocationPrice as NewFloatingMatrixWithAllocationPrice, +) +from .new_floating_threshold_total_amount_price import ( + NewFloatingThresholdTotalAmountPrice as NewFloatingThresholdTotalAmountPrice, +) +from .new_floating_cumulative_grouped_bulk_price import ( + NewFloatingCumulativeGroupedBulkPrice as NewFloatingCumulativeGroupedBulkPrice, +) +from .new_floating_package_with_allocation_price import ( + NewFloatingPackageWithAllocationPrice as NewFloatingPackageWithAllocationPrice, +) +from .new_plan_tiered_package_with_minimum_price import ( + NewPlanTieredPackageWithMinimumPrice as NewPlanTieredPackageWithMinimumPrice, +) +from .new_floating_matrix_with_display_name_price import ( + NewFloatingMatrixWithDisplayNamePrice as NewFloatingMatrixWithDisplayNamePrice, +) +from .new_floating_max_group_tiered_package_price import ( + NewFloatingMaxGroupTieredPackagePrice as NewFloatingMaxGroupTieredPackagePrice, +) +from .new_plan_grouped_with_metered_minimum_price import ( + NewPlanGroupedWithMeteredMinimumPrice as NewPlanGroupedWithMeteredMinimumPrice, +) +from .new_plan_grouped_with_prorated_minimum_price import ( + NewPlanGroupedWithProratedMinimumPrice as NewPlanGroupedWithProratedMinimumPrice, +) +from .new_floating_tiered_package_with_minimum_price import ( + NewFloatingTieredPackageWithMinimumPrice as NewFloatingTieredPackageWithMinimumPrice, +) +from .new_floating_grouped_with_metered_minimum_price import ( + NewFloatingGroupedWithMeteredMinimumPrice as NewFloatingGroupedWithMeteredMinimumPrice, +) +from .new_floating_grouped_with_prorated_minimum_price import ( + NewFloatingGroupedWithProratedMinimumPrice as NewFloatingGroupedWithProratedMinimumPrice, +) +from .new_plan_scalable_matrix_with_unit_pricing_price import ( + NewPlanScalableMatrixWithUnitPricingPrice as NewPlanScalableMatrixWithUnitPricingPrice, +) +from .new_plan_scalable_matrix_with_tiered_pricing_price import ( + NewPlanScalableMatrixWithTieredPricingPrice as NewPlanScalableMatrixWithTieredPricingPrice, +) +from .new_floating_scalable_matrix_with_unit_pricing_price import ( + NewFloatingScalableMatrixWithUnitPricingPrice as NewFloatingScalableMatrixWithUnitPricingPrice, +) +from .new_floating_scalable_matrix_with_tiered_pricing_price import ( + NewFloatingScalableMatrixWithTieredPricingPrice as NewFloatingScalableMatrixWithTieredPricingPrice, +) 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..035026dc --- /dev/null +++ b/src/orb/types/shared_params/amount_discount.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 Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["AmountDiscount", "Filter"] + + +class Filter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class AmountDiscount(TypedDict, total=False): + amount_discount: Required[str] + """Only available if discount_type is `amount`.""" + + discount_type: Required[Literal["amount"]] + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + filters: Optional[Iterable[Filter]] + """The filters that determine which prices to apply this discount to.""" + + reason: Optional[str] diff --git a/src/orb/types/shared_params/billing_cycle_anchor_configuration.py b/src/orb/types/shared_params/billing_cycle_anchor_configuration.py new file mode 100644 index 00000000..6df073fb --- /dev/null +++ b/src/orb/types/shared_params/billing_cycle_anchor_configuration.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +__all__ = ["BillingCycleAnchorConfiguration"] + + +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.). + """ diff --git a/src/orb/types/shared_params/billing_cycle_relative_date.py b/src/orb/types/shared_params/billing_cycle_relative_date.py new file mode 100644 index 00000000..5ac833ca --- /dev/null +++ b/src/orb/types/shared_params/billing_cycle_relative_date.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypeAlias + +__all__ = ["BillingCycleRelativeDate"] + +BillingCycleRelativeDate: TypeAlias = Literal["start_of_term", "end_of_term"] diff --git a/src/orb/types/shared_params/bulk_config.py b/src/orb/types/shared_params/bulk_config.py new file mode 100644 index 00000000..6c7bdb24 --- /dev/null +++ b/src/orb/types/shared_params/bulk_config.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +from .bulk_tier import BulkTier + +__all__ = ["BulkConfig"] + + +class BulkConfig(TypedDict, total=False): + """Configuration for bulk pricing""" + + tiers: Required[Iterable[BulkTier]] + """Bulk tiers for rating based on total usage volume""" diff --git a/src/orb/types/shared_params/bulk_tier.py b/src/orb/types/shared_params/bulk_tier.py new file mode 100644 index 00000000..1bac9c59 --- /dev/null +++ b/src/orb/types/shared_params/bulk_tier.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +__all__ = ["BulkTier"] + + +class BulkTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier""" + + unit_amount: Required[str] + """Amount per unit""" + + maximum_units: Optional[float] + """Upper bound for this tier""" diff --git a/src/orb/types/shared_params/conversion_rate_tier.py b/src/orb/types/shared_params/conversion_rate_tier.py new file mode 100644 index 00000000..8b8230a9 --- /dev/null +++ b/src/orb/types/shared_params/conversion_rate_tier.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +__all__ = ["ConversionRateTier"] + + +class ConversionRateTier(TypedDict, total=False): + first_unit: Required[float] + """Exclusive tier starting value""" + + unit_amount: Required[str] + """Amount per unit of overage""" + + last_unit: Optional[float] + """Inclusive tier ending value. If null, this is treated as the last tier""" diff --git a/src/orb/types/shared_params/conversion_rate_tiered_config.py b/src/orb/types/shared_params/conversion_rate_tiered_config.py new file mode 100644 index 00000000..bfb4362b --- /dev/null +++ b/src/orb/types/shared_params/conversion_rate_tiered_config.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +from .conversion_rate_tier import ConversionRateTier + +__all__ = ["ConversionRateTieredConfig"] + + +class ConversionRateTieredConfig(TypedDict, total=False): + tiers: Required[Iterable[ConversionRateTier]] + """Tiers for rating based on total usage quantities into the specified tier""" diff --git a/src/orb/types/shared_params/conversion_rate_unit_config.py b/src/orb/types/shared_params/conversion_rate_unit_config.py new file mode 100644 index 00000000..2bb9621b --- /dev/null +++ b/src/orb/types/shared_params/conversion_rate_unit_config.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ConversionRateUnitConfig"] + + +class ConversionRateUnitConfig(TypedDict, total=False): + unit_amount: Required[str] + """Amount per unit of overage""" diff --git a/src/orb/types/shared_params/custom_expiration.py b/src/orb/types/shared_params/custom_expiration.py new file mode 100644 index 00000000..cf55805f --- /dev/null +++ b/src/orb/types/shared_params/custom_expiration.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["CustomExpiration"] + + +class CustomExpiration(TypedDict, total=False): + duration: Required[int] + + duration_unit: Required[Literal["day", "month"]] diff --git a/src/orb/types/shared_params/customer_tax_id.py b/src/orb/types/shared_params/customer_tax_id.py new file mode 100644 index 00000000..2b30b77e --- /dev/null +++ b/src/orb/types/shared_params/customer_tax_id.py @@ -0,0 +1,407 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["CustomerTaxID"] + + +class CustomerTaxID(TypedDict, total=False): + """ + Tax IDs are commonly required to be displayed on customer invoices, which are added to the headers of invoices. + + + ### Supported Tax ID Countries and Types + + + | Country | Type | Description | + |---------|------|-------------| + | Albania | `al_tin` | Albania Tax Identification Number | + | Andorra | `ad_nrt` | Andorran NRT Number | + | Angola | `ao_tin` | Angola Tax Identification Number | + | Argentina | `ar_cuit` | Argentinian Tax ID Number | + | Armenia | `am_tin` | Armenia Tax Identification Number | + | Aruba | `aw_tin` | Aruba Tax Identification Number | + | Australia | `au_abn` | Australian Business Number (AU ABN) | + | Australia | `au_arn` | Australian Taxation Office Reference Number | + | Austria | `eu_vat` | European VAT Number | + | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number | + | Bahamas | `bs_tin` | Bahamas Tax Identification Number | + | Bahrain | `bh_vat` | Bahraini VAT Number | + | Bangladesh | `bd_bin` | Bangladesh Business Identification Number | + | Barbados | `bb_tin` | Barbados Tax Identification Number | + | Belarus | `by_tin` | Belarus TIN Number | + | Belgium | `eu_vat` | European VAT Number | + | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) | + | Bolivia | `bo_tin` | Bolivian Tax ID | + | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | + | Brazil | `br_cnpj` | Brazilian CNPJ Number | + | Brazil | `br_cpf` | Brazilian CPF Number | + | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code | + | Bulgaria | `eu_vat` | European VAT Number | + | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) | + | Cambodia | `kh_tin` | Cambodia Tax Identification Number | + | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) | + | Canada | `ca_bn` | Canadian BN | + | Canada | `ca_gst_hst` | Canadian GST/HST Number | + | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) | + | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | + | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + | Canada | `ca_qst` | Canadian QST Number (Québec) | + | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + | Chile | `cl_tin` | Chilean TIN | + | China | `cn_tin` | Chinese Tax ID | + | Colombia | `co_nit` | Colombian NIT Number | + | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + | Costa Rica | `cr_tin` | Costa Rican Tax ID | + | Croatia | `eu_vat` | European VAT Number | + | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) | + | Cyprus | `eu_vat` | European VAT Number | + | Czech Republic | `eu_vat` | European VAT Number | + | Denmark | `eu_vat` | European VAT Number | + | Dominican Republic | `do_rcn` | Dominican RCN Number | + | Ecuador | `ec_ruc` | Ecuadorian RUC Number | + | Egypt | `eg_tin` | Egyptian Tax Identification Number | + | El Salvador | `sv_nit` | El Salvadorian NIT Number | + | Estonia | `eu_vat` | European VAT Number | + | Ethiopia | `et_tin` | Ethiopia Tax Identification Number | + | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme | + | Faroe Islands | `fo_vat` | Faroe Islands VAT Number | + | Finland | `eu_vat` | European VAT Number | + | France | `eu_vat` | European VAT Number | + | Georgia | `ge_vat` | Georgian VAT | + | Germany | `de_stn` | German Tax Number (Steuernummer) | + | Germany | `eu_vat` | European VAT Number | + | Gibraltar | `gi_tin` | Gibraltar Tax Identification Number | + | Greece | `eu_vat` | European VAT Number | + | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) | + | Hong Kong | `hk_br` | Hong Kong BR Number | + | Hungary | `eu_vat` | European VAT Number | + | Hungary | `hu_tin` | Hungary Tax Number (adószám) | + | Iceland | `is_vat` | Icelandic VAT | + | India | `in_gst` | Indian GST Number | + | Indonesia | `id_npwp` | Indonesian NPWP Number | + | Ireland | `eu_vat` | European VAT Number | + | Israel | `il_vat` | Israel VAT | + | Italy | `eu_vat` | European VAT Number | + | Italy | `it_cf` | Italian Codice Fiscale Number | + | Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) | + | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | + | Japan | `jp_trn` | Japanese Tax Registration Number (*Tōroku Bangō*) | + | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number | + | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number | + | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number | + | Laos | `la_tin` | Laos Tax Identification Number | + | Latvia | `eu_vat` | European VAT Number | + | Liechtenstein | `li_uid` | Liechtensteinian UID Number | + | Liechtenstein | `li_vat` | Liechtenstein VAT Number | + | Lithuania | `eu_vat` | European VAT Number | + | Luxembourg | `eu_vat` | European VAT Number | + | Malaysia | `my_frp` | Malaysian FRP Number | + | Malaysia | `my_itn` | Malaysian ITN | + | Malaysia | `my_sst` | Malaysian SST Number | + | Malta | `eu_vat` | European VAT Number | + | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + | Mexico | `mx_rfc` | Mexican RFC Number | + | Moldova | `md_vat` | Moldova VAT Number | + | Montenegro | `me_pib` | Montenegro PIB Number | + | Morocco | `ma_vat` | Morocco VAT Number | + | Nepal | `np_pan` | Nepal PAN Number | + | Netherlands | `eu_vat` | European VAT Number | + | New Zealand | `nz_gst` | New Zealand GST Number | + | Nigeria | `ng_tin` | Nigerian Tax Identification Number | + | North Macedonia | `mk_vat` | North Macedonia VAT Number | + | Northern Ireland | `eu_vat` | Northern Ireland VAT Number | + | Norway | `no_vat` | Norwegian VAT Number | + | Norway | `no_voec` | Norwegian VAT on e-commerce Number | + | Oman | `om_vat` | Omani VAT Number | + | Paraguay | `py_ruc` | Paraguayan RUC Number | + | Peru | `pe_ruc` | Peruvian RUC Number | + | Philippines | `ph_tin` | Philippines Tax Identification Number | + | Poland | `eu_vat` | European VAT Number | + | Poland | `pl_nip` | Polish Tax ID Number | + | Portugal | `eu_vat` | European VAT Number | + | Romania | `eu_vat` | European VAT Number | + | Romania | `ro_tin` | Romanian Tax ID Number | + | Russia | `ru_inn` | Russian INN | + | Russia | `ru_kpp` | Russian KPP | + | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | + | Senegal | `sn_ninea` | Senegal NINEA Number | + | Serbia | `rs_pib` | Serbian PIB Number | + | Singapore | `sg_gst` | Singaporean GST | + | Singapore | `sg_uen` | Singaporean UEN | + | Slovakia | `eu_vat` | European VAT Number | + | Slovenia | `eu_vat` | European VAT Number | + | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) | + | South Africa | `za_vat` | South African VAT Number | + | South Korea | `kr_brn` | Korean BRN | + | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | + | Spain | `eu_vat` | European VAT Number | + | Sri Lanka | `lk_vat` | Sri Lanka VAT Number | + | Suriname | `sr_fin` | Suriname FIN Number | + | Sweden | `eu_vat` | European VAT Number | + | Switzerland | `ch_uid` | Switzerland UID Number | + | Switzerland | `ch_vat` | Switzerland VAT Number | + | Taiwan | `tw_vat` | Taiwanese VAT | + | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | + | Tanzania | `tz_vat` | Tanzania VAT Number | + | Thailand | `th_vat` | Thai VAT | + | Turkey | `tr_tin` | Turkish Tax Identification Number | + | Uganda | `ug_tin` | Uganda Tax Identification Number | + | Ukraine | `ua_vat` | Ukrainian VAT | + | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | + | United Kingdom | `gb_vat` | United Kingdom VAT Number | + | United States | `us_ein` | United States EIN | + | Uruguay | `uy_ruc` | Uruguayan RUC Number | + | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | + | Uzbekistan | `uz_vat` | Uzbekistan VAT Number | + | Venezuela | `ve_rif` | Venezuelan RIF Number | + | Vietnam | `vn_tin` | Vietnamese Tax ID Number | + | Zambia | `zm_tin` | Zambia Tax Identification Number | + | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | + """ + + country: Required[ + Literal[ + "AD", + "AE", + "AL", + "AM", + "AO", + "AR", + "AT", + "AU", + "AW", + "AZ", + "BA", + "BB", + "BD", + "BE", + "BF", + "BG", + "BH", + "BJ", + "BO", + "BR", + "BS", + "BY", + "CA", + "CD", + "CH", + "CL", + "CM", + "CN", + "CO", + "CR", + "CV", + "CY", + "CZ", + "DE", + "DK", + "DO", + "EC", + "EE", + "EG", + "ES", + "ET", + "EU", + "FI", + "FO", + "FR", + "GB", + "GE", + "GI", + "GN", + "GR", + "HK", + "HR", + "HU", + "ID", + "IE", + "IL", + "IN", + "IS", + "IT", + "JP", + "KE", + "KG", + "KH", + "KR", + "KZ", + "LA", + "LI", + "LK", + "LT", + "LU", + "LV", + "MA", + "MD", + "ME", + "MK", + "MR", + "MT", + "MX", + "MY", + "NG", + "NL", + "NO", + "NP", + "NZ", + "OM", + "PE", + "PH", + "PL", + "PT", + "PY", + "RO", + "RS", + "RU", + "SA", + "SE", + "SG", + "SI", + "SK", + "SN", + "SR", + "SV", + "TH", + "TJ", + "TR", + "TW", + "TZ", + "UA", + "UG", + "US", + "UY", + "UZ", + "VE", + "VN", + "ZA", + "ZM", + "ZW", + ] + ] + + type: Required[ + Literal[ + "ad_nrt", + "ae_trn", + "al_tin", + "am_tin", + "ao_tin", + "ar_cuit", + "eu_vat", + "au_abn", + "au_arn", + "aw_tin", + "az_tin", + "ba_tin", + "bb_tin", + "bd_bin", + "bf_ifu", + "bg_uic", + "bh_vat", + "bj_ifu", + "bo_tin", + "br_cnpj", + "br_cpf", + "bs_tin", + "by_tin", + "ca_bn", + "ca_gst_hst", + "ca_pst_bc", + "ca_pst_mb", + "ca_pst_sk", + "ca_qst", + "cd_nif", + "ch_uid", + "ch_vat", + "cl_tin", + "cm_niu", + "cn_tin", + "co_nit", + "cr_tin", + "cv_nif", + "de_stn", + "do_rcn", + "ec_ruc", + "eg_tin", + "es_cif", + "et_tin", + "eu_oss_vat", + "fo_vat", + "gb_vat", + "ge_vat", + "gi_tin", + "gn_nif", + "hk_br", + "hr_oib", + "hu_tin", + "id_npwp", + "il_vat", + "in_gst", + "is_vat", + "it_cf", + "jp_cn", + "jp_rn", + "jp_trn", + "ke_pin", + "kg_tin", + "kh_tin", + "kr_brn", + "kz_bin", + "la_tin", + "li_uid", + "li_vat", + "lk_vat", + "ma_vat", + "md_vat", + "me_pib", + "mk_vat", + "mr_nif", + "mx_rfc", + "my_frp", + "my_itn", + "my_sst", + "ng_tin", + "no_vat", + "no_voec", + "np_pan", + "nz_gst", + "om_vat", + "pe_ruc", + "ph_tin", + "pl_nip", + "py_ruc", + "ro_tin", + "rs_pib", + "ru_inn", + "ru_kpp", + "sa_vat", + "sg_gst", + "sg_uen", + "si_tin", + "sn_ninea", + "sr_fin", + "sv_nit", + "th_vat", + "tj_tin", + "tr_tin", + "tw_vat", + "tz_vat", + "ua_vat", + "ug_tin", + "us_ein", + "uy_ruc", + "uz_tin", + "uz_vat", + "ve_rif", + "vn_tin", + "za_vat", + "zm_tin", + "zw_tin", + ] + ] + + value: Required[str] diff --git a/src/orb/types/shared_params/discount.py b/src/orb/types/shared_params/discount.py new file mode 100644 index 00000000..bbdf05e5 --- /dev/null +++ b/src/orb/types/shared_params/discount.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..._types import SequenceNotStr +from .trial_discount import TrialDiscount +from .usage_discount import UsageDiscount +from .amount_discount import AmountDiscount +from .percentage_discount import PercentageDiscount + +__all__ = ["Discount", "TieredPercentageDiscount", "TieredPercentageDiscountTier", "TieredPercentageDiscountFilter"] + + +class TieredPercentageDiscountTier(TypedDict, total=False): + """One band of a tiered percentage discount. + + Bounds are denominated in the discount's currency. + `lower_bound` is the exclusive start of the band and `upper_bound` is the inclusive end; + `upper_bound` is null only for the open-ended final tier. + """ + + lower_bound: Required[float] + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: Required[float] + """ + The percentage (between 0 and 1) discounted from spend that falls within this + tier. + """ + + upper_bound: Optional[float] + """ + Inclusive upper bound of cumulative spend for this tier; null for the final + open-ended tier. + """ + + +class TieredPercentageDiscountFilter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class TieredPercentageDiscount(TypedDict, total=False): + discount_type: Required[Literal["tiered_percentage"]] + + tiers: Required[Iterable[TieredPercentageDiscountTier]] + """Only available if discount_type is `tiered_percentage`. + + The ordered, contiguous bands of cumulative eligible spend, each discounted at + its own percentage (progressive fill-a-tier). + """ + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + filters: Optional[Iterable[TieredPercentageDiscountFilter]] + """The filters that determine which prices to apply this discount to.""" + + reason: Optional[str] + + +Discount: TypeAlias = Union[PercentageDiscount, TrialDiscount, UsageDiscount, AmountDiscount, TieredPercentageDiscount] diff --git a/src/orb/types/shared_params/matrix_config.py b/src/orb/types/shared_params/matrix_config.py new file mode 100644 index 00000000..94ba879b --- /dev/null +++ b/src/orb/types/shared_params/matrix_config.py @@ -0,0 +1,24 @@ +# 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 Required, TypedDict + +from ..._types import SequenceNotStr +from .matrix_value import MatrixValue + +__all__ = ["MatrixConfig"] + + +class MatrixConfig(TypedDict, total=False): + """Configuration for matrix pricing""" + + default_unit_amount: Required[str] + """Default per unit rate for any usage not bucketed into a specified matrix_value""" + + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" + + matrix_values: Required[Iterable[MatrixValue]] + """Matrix values configuration""" diff --git a/src/orb/types/shared_params/matrix_value.py b/src/orb/types/shared_params/matrix_value.py new file mode 100644 index 00000000..b6879ac4 --- /dev/null +++ b/src/orb/types/shared_params/matrix_value.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["MatrixValue"] + + +class MatrixValue(TypedDict, total=False): + """Configuration for a single matrix value""" + + dimension_values: Required[SequenceNotStr[Optional[str]]] + """One or two matrix keys to filter usage to this Matrix value by""" + + unit_amount: Required[str] + """Unit price for the specified dimension_values""" diff --git a/src/orb/types/shared_params/matrix_with_allocation_config.py b/src/orb/types/shared_params/matrix_with_allocation_config.py new file mode 100644 index 00000000..30af0b0d --- /dev/null +++ b/src/orb/types/shared_params/matrix_with_allocation_config.py @@ -0,0 +1,40 @@ +# 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 Required, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["MatrixWithAllocationConfig", "MatrixValue"] + + +class MatrixValue(TypedDict, total=False): + """Configuration for a single matrix value""" + + dimension_values: Required[SequenceNotStr[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 MatrixWithAllocationConfig(TypedDict, total=False): + """Configuration for matrix pricing with usage allocation""" + + allocation: Required[str] + """Usage allocation""" + + default_unit_amount: Required[str] + """Default per unit rate for any usage not bucketed into a specified matrix_value""" + + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" + + matrix_values: Required[Iterable[MatrixValue]] + """Matrix values configuration""" diff --git a/src/orb/types/shared_params/new_allocation_price.py b/src/orb/types/shared_params/new_allocation_price.py new file mode 100644 index 00000000..54500bea --- /dev/null +++ b/src/orb/types/shared_params/new_allocation_price.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from ..._types import SequenceNotStr +from .custom_expiration import CustomExpiration + +__all__ = ["NewAllocationPrice", "Filter"] + + +class Filter(TypedDict, total=False): + """A PriceFilter that only allows item_id field for block filters.""" + + field: Required[Literal["item_id"]] + """The property of the price the block applies to. Only item_id is supported.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class NewAllocationPrice(TypedDict, total=False): + amount: Required[str] + """An amount of the currency to allocate to the customer at the specified cadence.""" + + cadence: Required[Literal["one_time", "monthly", "quarterly", "semi_annual", "annual"]] + """The cadence at which to allocate the amount to the customer.""" + + currency: Required[str] + """ + An ISO 4217 currency string or a custom pricing unit identifier in which to bill + this price. + """ + + custom_expiration: Optional[CustomExpiration] + """The custom expiration for the allocation.""" + + expires_at_end_of_cadence: Optional[bool] + """ + Whether the allocated amount should expire at the end of the cadence or roll + over to the next period. Set to null if using custom_expiration. + """ + + filters: Optional[Iterable[Filter]] + """The filters that determine which items the allocation applies to.""" + + item_id: Optional[str] + """ + The item ID that line items representing charges for this allocation will be + associated with. If not provided, the default allocation item for the currency + will be used (e.g. 'Included Allocation (USD)'). + """ + + license_type_id: Optional[str] + """The license type ID to associate the price with license allocation.""" + + 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`. + """ + + per_unit_cost_basis: str + """The (per-unit) cost basis of each created block. + + If non-zero, a customer will be invoiced according to the quantity and per unit + cost basis specified for the allocation each cadence. + """ diff --git a/src/orb/types/shared_params/new_amount_discount.py b/src/orb/types/shared_params/new_amount_discount.py new file mode 100644 index 00000000..ad213823 --- /dev/null +++ b/src/orb/types/shared_params/new_amount_discount.py @@ -0,0 +1,51 @@ +# 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 + +from ..._types import SequenceNotStr + +__all__ = ["NewAmountDiscount", "Filter"] + + +class Filter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class NewAmountDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["amount_discount"]] + + amount_discount: Required[str] + + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[Iterable[Filter]] + """A list of filters that determine which prices this adjustment will apply to.""" + + 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. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" diff --git a/src/orb/types/shared_params/new_billing_cycle_configuration.py b/src/orb/types/shared_params/new_billing_cycle_configuration.py new file mode 100644 index 00000000..bb63dabb --- /dev/null +++ b/src/orb/types/shared_params/new_billing_cycle_configuration.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["NewBillingCycleConfiguration"] + + +class NewBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" diff --git a/src/orb/types/shared_params/new_dimensional_price_configuration.py b/src/orb/types/shared_params/new_dimensional_price_configuration.py new file mode 100644 index 00000000..a75a271e --- /dev/null +++ b/src/orb/types/shared_params/new_dimensional_price_configuration.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["NewDimensionalPriceConfiguration"] + + +class NewDimensionalPriceConfiguration(TypedDict, total=False): + dimension_values: Required[SequenceNotStr[str]] + """ + The list of dimension values matching (in order) the dimensions of the price + group + """ + + dimensional_price_group_id: Optional[str] + """The id of the dimensional price group to include this price in""" + + external_dimensional_price_group_id: Optional[str] + """The external id of the dimensional price group to include this price in""" diff --git a/src/orb/types/shared_params/new_floating_bulk_price.py b/src/orb/types/shared_params/new_floating_bulk_price.py new file mode 100644 index 00000000..da009a94 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_bulk_price.py @@ -0,0 +1,91 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .bulk_config import BulkConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingBulkPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingBulkPrice(TypedDict, total=False): + bulk_config: Required[BulkConfig] + """Configuration for bulk pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_bulk_with_proration_price.py b/src/orb/types/shared_params/new_floating_bulk_with_proration_price.py new file mode 100644 index 00000000..14152f72 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_bulk_with_proration_price.py @@ -0,0 +1,113 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingBulkWithProrationPrice", + "BulkWithProrationConfig", + "BulkWithProrationConfigTier", + "ConversionRateConfig", +] + + +class BulkWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier with proration""" + + unit_amount: Required[str] + """Cost per unit""" + + tier_lower_bound: Optional[str] + """The lower bound for this tier""" + + +class BulkWithProrationConfig(TypedDict, total=False): + """Configuration for bulk_with_proration pricing""" + + tiers: Required[Iterable[BulkWithProrationConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingBulkWithProrationPrice(TypedDict, total=False): + bulk_with_proration_config: Required[BulkWithProrationConfig] + """Configuration for bulk_with_proration pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk_with_proration"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_cumulative_grouped_bulk_price.py b/src/orb/types/shared_params/new_floating_cumulative_grouped_bulk_price.py new file mode 100644 index 00000000..7c13aea1 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_cumulative_grouped_bulk_price.py @@ -0,0 +1,118 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingCumulativeGroupedBulkPrice", + "CumulativeGroupedBulkConfig", + "CumulativeGroupedBulkConfigDimensionValue", + "ConversionRateConfig", +] + + +class CumulativeGroupedBulkConfigDimensionValue(TypedDict, total=False): + """Configuration for a dimension value entry""" + + grouping_key: Required[str] + """Grouping key value""" + + tier_lower_bound: Required[str] + """Tier lower bound""" + + unit_amount: Required[str] + """Unit amount for this combination""" + + +class CumulativeGroupedBulkConfig(TypedDict, total=False): + """Configuration for cumulative_grouped_bulk pricing""" + + dimension_values: Required[Iterable[CumulativeGroupedBulkConfigDimensionValue]] + """Each tier lower bound must have the same group of values.""" + + group: Required[str] + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingCumulativeGroupedBulkPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_bulk_config: Required[CumulativeGroupedBulkConfig] + """Configuration for cumulative_grouped_bulk pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_bulk"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_grouped_allocation_price.py b/src/orb/types/shared_params/new_floating_grouped_allocation_price.py new file mode 100644 index 00000000..b1d570be --- /dev/null +++ b/src/orb/types/shared_params/new_floating_grouped_allocation_price.py @@ -0,0 +1,104 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingGroupedAllocationPrice", "GroupedAllocationConfig", "ConversionRateConfig"] + + +class GroupedAllocationConfig(TypedDict, total=False): + """Configuration for grouped_allocation pricing""" + + allocation: Required[str] + """Usage allocation per group""" + + grouping_key: Required[str] + """How to determine the groups that should each be allocated some quantity""" + + overage_unit_rate: Required[str] + """Unit rate for post-allocation""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingGroupedAllocationPrice(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_allocation_config: Required[GroupedAllocationConfig] + """Configuration for grouped_allocation pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_grouped_tiered_package_price.py b/src/orb/types/shared_params/new_floating_grouped_tiered_package_price.py new file mode 100644 index 00000000..2d7fbd53 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_grouped_tiered_package_price.py @@ -0,0 +1,120 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingGroupedTieredPackagePrice", + "GroupedTieredPackageConfig", + "GroupedTieredPackageConfigTier", + "ConversionRateConfig", +] + + +class GroupedTieredPackageConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + per_unit: Required[str] + """Per package""" + + tier_lower_bound: Required[str] + + +class GroupedTieredPackageConfig(TypedDict, total=False): + """Configuration for grouped_tiered_package pricing""" + + grouping_key: Required[str] + """The event property used to group before tiering""" + + package_size: Required[str] + + tiers: Required[Iterable[GroupedTieredPackageConfigTier]] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingGroupedTieredPackagePrice(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_tiered_package_config: Required[GroupedTieredPackageConfig] + """Configuration for grouped_tiered_package pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_tiered_package"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_grouped_tiered_price.py b/src/orb/types/shared_params/new_floating_grouped_tiered_price.py new file mode 100644 index 00000000..14fd31d5 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_grouped_tiered_price.py @@ -0,0 +1,113 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingGroupedTieredPrice", "GroupedTieredConfig", "GroupedTieredConfigTier", "ConversionRateConfig"] + + +class GroupedTieredConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + tier_lower_bound: Required[str] + + unit_amount: Required[str] + """Per unit amount""" + + +class GroupedTieredConfig(TypedDict, total=False): + """Configuration for grouped_tiered pricing""" + + grouping_key: Required[str] + """The billable metric property used to group before tiering""" + + tiers: Required[Iterable[GroupedTieredConfigTier]] + """ + Apply tiered pricing to each segment generated after grouping with the provided + key + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingGroupedTieredPrice(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_tiered_config: Required[GroupedTieredConfig] + """Configuration for grouped_tiered pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_tiered"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_grouped_with_metered_minimum_price.py b/src/orb/types/shared_params/new_floating_grouped_with_metered_minimum_price.py new file mode 100644 index 00000000..d722c98d --- /dev/null +++ b/src/orb/types/shared_params/new_floating_grouped_with_metered_minimum_price.py @@ -0,0 +1,142 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingGroupedWithMeteredMinimumPrice", + "GroupedWithMeteredMinimumConfig", + "GroupedWithMeteredMinimumConfigScalingFactor", + "GroupedWithMeteredMinimumConfigUnitAmount", + "ConversionRateConfig", +] + + +class GroupedWithMeteredMinimumConfigScalingFactor(TypedDict, total=False): + """Configuration for a scaling factor""" + + scaling_factor: Required[str] + + scaling_value: Required[str] + + +class GroupedWithMeteredMinimumConfigUnitAmount(TypedDict, total=False): + """Configuration for a unit amount""" + + pricing_value: Required[str] + + unit_amount: Required[str] + """Per unit amount""" + + +class GroupedWithMeteredMinimumConfig(TypedDict, total=False): + """Configuration for grouped_with_metered_minimum pricing""" + + grouping_key: Required[str] + """Used to partition the usage into groups. + + The minimum amount is applied to each group. + """ + + minimum_unit_amount: Required[str] + """The minimum amount to charge per group per unit""" + + pricing_key: Required[str] + """Used to determine the unit rate""" + + scaling_factors: Required[Iterable[GroupedWithMeteredMinimumConfigScalingFactor]] + """Scale the unit rates by the scaling factor.""" + + scaling_key: Required[str] + """Used to determine the unit rate scaling factor""" + + unit_amounts: Required[Iterable[GroupedWithMeteredMinimumConfigUnitAmount]] + """Apply per unit pricing to each pricing value. + + The minimum amount is applied any unmatched usage. + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +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[GroupedWithMeteredMinimumConfig] + """Configuration for grouped_with_metered_minimum pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_metered_minimum"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_grouped_with_prorated_minimum_price.py b/src/orb/types/shared_params/new_floating_grouped_with_prorated_minimum_price.py new file mode 100644 index 00000000..fd793161 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_grouped_with_prorated_minimum_price.py @@ -0,0 +1,104 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingGroupedWithProratedMinimumPrice", "GroupedWithProratedMinimumConfig", "ConversionRateConfig"] + + +class GroupedWithProratedMinimumConfig(TypedDict, total=False): + """Configuration for grouped_with_prorated_minimum pricing""" + + grouping_key: Required[str] + """How to determine the groups that should each have a minimum""" + + minimum: Required[str] + """The minimum amount to charge per group""" + + unit_rate: Required[str] + """The amount to charge per unit""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingGroupedWithProratedMinimumPrice(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_prorated_minimum_config: Required[GroupedWithProratedMinimumConfig] + """Configuration for grouped_with_prorated_minimum pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_prorated_minimum"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_matrix_price.py b/src/orb/types/shared_params/new_floating_matrix_price.py new file mode 100644 index 00000000..23d131c8 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_matrix_price.py @@ -0,0 +1,91 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .matrix_config import MatrixConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingMatrixPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingMatrixPrice(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 price will be associated with.""" + + matrix_config: Required[MatrixConfig] + """Configuration for matrix pricing""" + + model_type: Required[Literal["matrix"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_matrix_with_allocation_price.py b/src/orb/types/shared_params/new_floating_matrix_with_allocation_price.py new file mode 100644 index 00000000..7a625e3c --- /dev/null +++ b/src/orb/types/shared_params/new_floating_matrix_with_allocation_price.py @@ -0,0 +1,91 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .matrix_with_allocation_config import MatrixWithAllocationConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingMatrixWithAllocationPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingMatrixWithAllocationPrice(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 price will be associated with.""" + + matrix_with_allocation_config: Required[MatrixWithAllocationConfig] + """Configuration for matrix_with_allocation pricing""" + + model_type: Required[Literal["matrix_with_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_matrix_with_display_name_price.py b/src/orb/types/shared_params/new_floating_matrix_with_display_name_price.py new file mode 100644 index 00000000..de083d01 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_matrix_with_display_name_price.py @@ -0,0 +1,119 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingMatrixWithDisplayNamePrice", + "MatrixWithDisplayNameConfig", + "MatrixWithDisplayNameConfigUnitAmount", + "ConversionRateConfig", +] + + +class MatrixWithDisplayNameConfigUnitAmount(TypedDict, total=False): + """Configuration for a unit amount item""" + + dimension_value: Required[str] + """The dimension value""" + + display_name: Required[str] + """Display name for this dimension value""" + + unit_amount: Required[str] + """Per unit amount""" + + +class MatrixWithDisplayNameConfig(TypedDict, total=False): + """Configuration for matrix_with_display_name pricing""" + + dimension: Required[str] + """Used to determine the unit rate""" + + unit_amounts: Required[Iterable[MatrixWithDisplayNameConfigUnitAmount]] + """Apply per unit pricing to each dimension value""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +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 price will be associated with.""" + + matrix_with_display_name_config: Required[MatrixWithDisplayNameConfig] + """Configuration for matrix_with_display_name pricing""" + + model_type: Required[Literal["matrix_with_display_name"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_max_group_tiered_package_price.py b/src/orb/types/shared_params/new_floating_max_group_tiered_package_price.py new file mode 100644 index 00000000..d5e6fe1c --- /dev/null +++ b/src/orb/types/shared_params/new_floating_max_group_tiered_package_price.py @@ -0,0 +1,119 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingMaxGroupTieredPackagePrice", + "MaxGroupTieredPackageConfig", + "MaxGroupTieredPackageConfigTier", + "ConversionRateConfig", +] + + +class MaxGroupTieredPackageConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + tier_lower_bound: Required[str] + + unit_amount: Required[str] + """Per unit amount""" + + +class MaxGroupTieredPackageConfig(TypedDict, total=False): + """Configuration for max_group_tiered_package pricing""" + + grouping_key: Required[str] + """ + The event property used to group before tiering the group with the highest value + """ + + package_size: Required[str] + + tiers: Required[Iterable[MaxGroupTieredPackageConfigTier]] + """Apply tiered pricing to the largest group after grouping with the provided key.""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingMaxGroupTieredPackagePrice(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 price will be associated with.""" + + max_group_tiered_package_config: Required[MaxGroupTieredPackageConfig] + """Configuration for max_group_tiered_package pricing""" + + model_type: Required[Literal["max_group_tiered_package"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_minimum_composite_price.py b/src/orb/types/shared_params/new_floating_minimum_composite_price.py new file mode 100644 index 00000000..286cc7c3 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_minimum_composite_price.py @@ -0,0 +1,101 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingMinimumCompositePrice", "MinimumCompositeConfig", "ConversionRateConfig"] + + +class MinimumCompositeConfig(TypedDict, total=False): + """Configuration for minimum_composite pricing""" + + minimum_amount: Required[str] + """The minimum amount to apply""" + + prorated: bool + """If true, subtotals from this price are prorated based on the service period""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingMinimumCompositePrice(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 price will be associated with.""" + + minimum_composite_config: Required[MinimumCompositeConfig] + """Configuration for minimum_composite pricing""" + + model_type: Required[Literal["minimum_composite"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_package_price.py b/src/orb/types/shared_params/new_floating_package_price.py new file mode 100644 index 00000000..80bda543 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_package_price.py @@ -0,0 +1,91 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .package_config import PackageConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingPackagePrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingPackagePrice(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 price will be associated with.""" + + model_type: Required[Literal["package"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + package_config: Required[PackageConfig] + """Configuration for package pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_package_with_allocation_price.py b/src/orb/types/shared_params/new_floating_package_with_allocation_price.py new file mode 100644 index 00000000..fd11087b --- /dev/null +++ b/src/orb/types/shared_params/new_floating_package_with_allocation_price.py @@ -0,0 +1,101 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingPackageWithAllocationPrice", "PackageWithAllocationConfig", "ConversionRateConfig"] + + +class PackageWithAllocationConfig(TypedDict, total=False): + """Configuration for package_with_allocation pricing""" + + allocation: Required[str] + + package_amount: Required[str] + + package_size: Required[str] + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingPackageWithAllocationPrice(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 price will be associated with.""" + + model_type: Required[Literal["package_with_allocation"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + package_with_allocation_config: Required[PackageWithAllocationConfig] + """Configuration for package_with_allocation pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_scalable_matrix_with_tiered_pricing_price.py b/src/orb/types/shared_params/new_floating_scalable_matrix_with_tiered_pricing_price.py new file mode 100644 index 00000000..3d77020e --- /dev/null +++ b/src/orb/types/shared_params/new_floating_scalable_matrix_with_tiered_pricing_price.py @@ -0,0 +1,130 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingScalableMatrixWithTieredPricingPrice", + "ScalableMatrixWithTieredPricingConfig", + "ScalableMatrixWithTieredPricingConfigMatrixScalingFactor", + "ScalableMatrixWithTieredPricingConfigTier", + "ConversionRateConfig", +] + + +class ScalableMatrixWithTieredPricingConfigMatrixScalingFactor(TypedDict, total=False): + """Configuration for a single matrix scaling factor""" + + first_dimension_value: Required[str] + + scaling_factor: Required[str] + + second_dimension_value: Optional[str] + + +class ScalableMatrixWithTieredPricingConfigTier(TypedDict, total=False): + """Configuration for a single tier entry with business logic""" + + tier_lower_bound: Required[str] + + unit_amount: Required[str] + + +class ScalableMatrixWithTieredPricingConfig(TypedDict, total=False): + """Configuration for scalable_matrix_with_tiered_pricing pricing""" + + first_dimension: Required[str] + """Used for the scalable matrix first dimension""" + + matrix_scaling_factors: Required[Iterable[ScalableMatrixWithTieredPricingConfigMatrixScalingFactor]] + """Apply a scaling factor to each dimension""" + + tiers: Required[Iterable[ScalableMatrixWithTieredPricingConfigTier]] + + second_dimension: Optional[str] + """Used for the scalable matrix second dimension (optional)""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingScalableMatrixWithTieredPricingPrice(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 price will be associated with.""" + + model_type: Required[Literal["scalable_matrix_with_tiered_pricing"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + scalable_matrix_with_tiered_pricing_config: Required[ScalableMatrixWithTieredPricingConfig] + """Configuration for scalable_matrix_with_tiered_pricing pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_scalable_matrix_with_unit_pricing_price.py b/src/orb/types/shared_params/new_floating_scalable_matrix_with_unit_pricing_price.py new file mode 100644 index 00000000..009b8569 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_scalable_matrix_with_unit_pricing_price.py @@ -0,0 +1,128 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingScalableMatrixWithUnitPricingPrice", + "ScalableMatrixWithUnitPricingConfig", + "ScalableMatrixWithUnitPricingConfigMatrixScalingFactor", + "ConversionRateConfig", +] + + +class ScalableMatrixWithUnitPricingConfigMatrixScalingFactor(TypedDict, total=False): + """Configuration for a single matrix scaling factor""" + + first_dimension_value: Required[str] + + scaling_factor: Required[str] + + second_dimension_value: Optional[str] + + +class ScalableMatrixWithUnitPricingConfig(TypedDict, total=False): + """Configuration for scalable_matrix_with_unit_pricing pricing""" + + first_dimension: Required[str] + """Used to determine the unit rate""" + + matrix_scaling_factors: Required[Iterable[ScalableMatrixWithUnitPricingConfigMatrixScalingFactor]] + """Apply a scaling factor to each dimension""" + + unit_price: Required[str] + """The final unit price to rate against the output of the matrix""" + + grouping_key: Optional[str] + """The property used to group this price""" + + prorate: Optional[bool] + """If true, the unit price will be prorated to the billing period""" + + second_dimension: Optional[str] + """Used to determine the unit rate (optional)""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingScalableMatrixWithUnitPricingPrice(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 price will be associated with.""" + + model_type: Required[Literal["scalable_matrix_with_unit_pricing"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + scalable_matrix_with_unit_pricing_config: Required[ScalableMatrixWithUnitPricingConfig] + """Configuration for scalable_matrix_with_unit_pricing pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_threshold_total_amount_price.py b/src/orb/types/shared_params/new_floating_threshold_total_amount_price.py new file mode 100644 index 00000000..a6eadaa0 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_threshold_total_amount_price.py @@ -0,0 +1,118 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingThresholdTotalAmountPrice", + "ThresholdTotalAmountConfig", + "ThresholdTotalAmountConfigConsumptionTable", + "ConversionRateConfig", +] + + +class ThresholdTotalAmountConfigConsumptionTable(TypedDict, total=False): + """Configuration for a single threshold""" + + threshold: Required[str] + + total_amount: Required[str] + """Total amount for this threshold""" + + +class ThresholdTotalAmountConfig(TypedDict, total=False): + """Configuration for threshold_total_amount pricing""" + + consumption_table: Required[Iterable[ThresholdTotalAmountConfigConsumptionTable]] + """ + When the quantity consumed passes a provided threshold, the configured total + will be charged + """ + + prorate: Optional[bool] + """If true, the unit price will be prorated to the billing period""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingThresholdTotalAmountPrice(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 price will be associated with.""" + + model_type: Required[Literal["threshold_total_amount"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + threshold_total_amount_config: Required[ThresholdTotalAmountConfig] + """Configuration for threshold_total_amount pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_tiered_package_price.py b/src/orb/types/shared_params/new_floating_tiered_package_price.py new file mode 100644 index 00000000..f4e0fb24 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_tiered_package_price.py @@ -0,0 +1,114 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingTieredPackagePrice", "TieredPackageConfig", "TieredPackageConfigTier", "ConversionRateConfig"] + + +class TieredPackageConfigTier(TypedDict, total=False): + """Configuration for a single tier with business logic""" + + per_unit: Required[str] + """Price per package""" + + tier_lower_bound: Required[str] + + +class TieredPackageConfig(TypedDict, total=False): + """Configuration for tiered_package pricing""" + + package_size: Required[str] + + tiers: Required[Iterable[TieredPackageConfigTier]] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. The tier bounds are defined + based on the total quantity rather than the number of packages, so they must be + multiples of the package size. + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingTieredPackagePrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered_package"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_package_config: Required[TieredPackageConfig] + """Configuration for tiered_package pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_tiered_package_with_minimum_price.py b/src/orb/types/shared_params/new_floating_tiered_package_with_minimum_price.py new file mode 100644 index 00000000..9f873b91 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_tiered_package_with_minimum_price.py @@ -0,0 +1,118 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingTieredPackageWithMinimumPrice", + "TieredPackageWithMinimumConfig", + "TieredPackageWithMinimumConfigTier", + "ConversionRateConfig", +] + + +class TieredPackageWithMinimumConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + minimum_amount: Required[str] + + per_unit: Required[str] + + tier_lower_bound: Required[str] + + +class TieredPackageWithMinimumConfig(TypedDict, total=False): + """Configuration for tiered_package_with_minimum pricing""" + + package_size: Required[float] + + tiers: Required[Iterable[TieredPackageWithMinimumConfigTier]] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingTieredPackageWithMinimumPrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered_package_with_minimum"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_package_with_minimum_config: Required[TieredPackageWithMinimumConfig] + """Configuration for tiered_package_with_minimum pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_tiered_price.py b/src/orb/types/shared_params/new_floating_tiered_price.py new file mode 100644 index 00000000..66e2ae84 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_tiered_price.py @@ -0,0 +1,91 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .tiered_config import TieredConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingTieredPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingTieredPrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_config: Required[TieredConfig] + """Configuration for tiered pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_tiered_with_minimum_price.py b/src/orb/types/shared_params/new_floating_tiered_with_minimum_price.py new file mode 100644 index 00000000..c1ebb6c0 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_tiered_with_minimum_price.py @@ -0,0 +1,123 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingTieredWithMinimumPrice", + "TieredWithMinimumConfig", + "TieredWithMinimumConfigTier", + "ConversionRateConfig", +] + + +class TieredWithMinimumConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + minimum_amount: Required[str] + + tier_lower_bound: Required[str] + + unit_amount: Required[str] + """Per unit amount""" + + +class TieredWithMinimumConfig(TypedDict, total=False): + """Configuration for tiered_with_minimum pricing""" + + tiers: Required[Iterable[TieredWithMinimumConfigTier]] + """Tiered pricing with a minimum amount dependent on the volume tier. + + Tiers are defined using exclusive lower bounds. + """ + + hide_zero_amount_tiers: bool + """If true, tiers with an accrued amount of 0 will not be included in the rating.""" + + prorate: bool + """If true, the unit price will be prorated to the billing period""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingTieredWithMinimumPrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered_with_minimum"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_with_minimum_config: Required[TieredWithMinimumConfig] + """Configuration for tiered_with_minimum pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_tiered_with_proration_price.py b/src/orb/types/shared_params/new_floating_tiered_with_proration_price.py new file mode 100644 index 00000000..815c98d9 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_tiered_with_proration_price.py @@ -0,0 +1,116 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewFloatingTieredWithProrationPrice", + "TieredWithProrationConfig", + "TieredWithProrationConfigTier", + "ConversionRateConfig", +] + + +class TieredWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single tiered with proration tier""" + + tier_lower_bound: Required[str] + """Inclusive tier starting value""" + + unit_amount: Required[str] + """Amount per unit""" + + +class TieredWithProrationConfig(TypedDict, total=False): + """Configuration for tiered_with_proration pricing""" + + tiers: Required[Iterable[TieredWithProrationConfigTier]] + """ + Tiers for rating based on total usage quantities into the specified tier with + proration + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingTieredWithProrationPrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered_with_proration"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_with_proration_config: Required[TieredWithProrationConfig] + """Configuration for tiered_with_proration pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_unit_price.py b/src/orb/types/shared_params/new_floating_unit_price.py new file mode 100644 index 00000000..8a7cfc66 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_unit_price.py @@ -0,0 +1,91 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_config import UnitConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingUnitPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingUnitPrice(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 price will be associated with.""" + + model_type: Required[Literal["unit"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_config: Required[UnitConfig] + """Configuration for unit pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_unit_with_percent_price.py b/src/orb/types/shared_params/new_floating_unit_with_percent_price.py new file mode 100644 index 00000000..a325cfab --- /dev/null +++ b/src/orb/types/shared_params/new_floating_unit_with_percent_price.py @@ -0,0 +1,101 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingUnitWithPercentPrice", "UnitWithPercentConfig", "ConversionRateConfig"] + + +class UnitWithPercentConfig(TypedDict, total=False): + """Configuration for unit_with_percent pricing""" + + percent: Required[str] + """What percent, out of 100, of the calculated total to charge""" + + unit_amount: Required[str] + """Rate per unit of usage""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingUnitWithPercentPrice(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 price will be associated with.""" + + model_type: Required[Literal["unit_with_percent"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_with_percent_config: Required[UnitWithPercentConfig] + """Configuration for unit_with_percent pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_floating_unit_with_proration_price.py b/src/orb/types/shared_params/new_floating_unit_with_proration_price.py new file mode 100644 index 00000000..737d7d10 --- /dev/null +++ b/src/orb/types/shared_params/new_floating_unit_with_proration_price.py @@ -0,0 +1,98 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewFloatingUnitWithProrationPrice", "UnitWithProrationConfig", "ConversionRateConfig"] + + +class UnitWithProrationConfig(TypedDict, total=False): + """Configuration for unit_with_proration pricing""" + + unit_amount: Required[str] + """Rate per unit of usage""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewFloatingUnitWithProrationPrice(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 price will be associated with.""" + + model_type: Required[Literal["unit_with_proration"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_with_proration_config: Required[UnitWithProrationConfig] + """Configuration for unit_with_proration pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ diff --git a/src/orb/types/shared_params/new_maximum.py b/src/orb/types/shared_params/new_maximum.py new file mode 100644 index 00000000..f79bfe25 --- /dev/null +++ b/src/orb/types/shared_params/new_maximum.py @@ -0,0 +1,51 @@ +# 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 + +from ..._types import SequenceNotStr + +__all__ = ["NewMaximum", "Filter"] + + +class Filter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class NewMaximum(TypedDict, total=False): + adjustment_type: Required[Literal["maximum"]] + + maximum_amount: Required[str] + + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[Iterable[Filter]] + """A list of filters that determine which prices this adjustment will apply to.""" + + 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. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" diff --git a/src/orb/types/shared_params/new_minimum.py b/src/orb/types/shared_params/new_minimum.py new file mode 100644 index 00000000..0c1bb520 --- /dev/null +++ b/src/orb/types/shared_params/new_minimum.py @@ -0,0 +1,54 @@ +# 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 + +from ..._types import SequenceNotStr + +__all__ = ["NewMinimum", "Filter"] + + +class Filter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class NewMinimum(TypedDict, total=False): + adjustment_type: Required[Literal["minimum"]] + + item_id: Required[str] + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: Required[str] + + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[Iterable[Filter]] + """A list of filters that determine which prices this adjustment will apply to.""" + + 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. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" diff --git a/src/orb/types/shared_params/new_percentage_discount.py b/src/orb/types/shared_params/new_percentage_discount.py new file mode 100644 index 00000000..b227a57f --- /dev/null +++ b/src/orb/types/shared_params/new_percentage_discount.py @@ -0,0 +1,51 @@ +# 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 + +from ..._types import SequenceNotStr + +__all__ = ["NewPercentageDiscount", "Filter"] + + +class Filter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class NewPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["percentage_discount"]] + + percentage_discount: Required[float] + + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[Iterable[Filter]] + """A list of filters that determine which prices this adjustment will apply to.""" + + 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. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" diff --git a/src/orb/types/shared_params/new_plan_bulk_price.py b/src/orb/types/shared_params/new_plan_bulk_price.py new file mode 100644 index 00000000..18365957 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_bulk_price.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .bulk_config import BulkConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanBulkPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanBulkPrice(TypedDict, total=False): + bulk_config: Required[BulkConfig] + """Configuration for bulk pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_bulk_with_proration_price.py b/src/orb/types/shared_params/new_plan_bulk_with_proration_price.py new file mode 100644 index 00000000..98c81479 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_bulk_with_proration_price.py @@ -0,0 +1,122 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanBulkWithProrationPrice", + "BulkWithProrationConfig", + "BulkWithProrationConfigTier", + "ConversionRateConfig", +] + + +class BulkWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier with proration""" + + unit_amount: Required[str] + """Cost per unit""" + + tier_lower_bound: Optional[str] + """The lower bound for this tier""" + + +class BulkWithProrationConfig(TypedDict, total=False): + """Configuration for bulk_with_proration pricing""" + + tiers: Required[Iterable[BulkWithProrationConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanBulkWithProrationPrice(TypedDict, total=False): + bulk_with_proration_config: Required[BulkWithProrationConfig] + """Configuration for bulk_with_proration pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk_with_proration"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_cumulative_grouped_bulk_price.py b/src/orb/types/shared_params/new_plan_cumulative_grouped_bulk_price.py new file mode 100644 index 00000000..8f855259 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_cumulative_grouped_bulk_price.py @@ -0,0 +1,127 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanCumulativeGroupedBulkPrice", + "CumulativeGroupedBulkConfig", + "CumulativeGroupedBulkConfigDimensionValue", + "ConversionRateConfig", +] + + +class CumulativeGroupedBulkConfigDimensionValue(TypedDict, total=False): + """Configuration for a dimension value entry""" + + grouping_key: Required[str] + """Grouping key value""" + + tier_lower_bound: Required[str] + """Tier lower bound""" + + unit_amount: Required[str] + """Unit amount for this combination""" + + +class CumulativeGroupedBulkConfig(TypedDict, total=False): + """Configuration for cumulative_grouped_bulk pricing""" + + dimension_values: Required[Iterable[CumulativeGroupedBulkConfigDimensionValue]] + """Each tier lower bound must have the same group of values.""" + + group: Required[str] + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanCumulativeGroupedBulkPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_bulk_config: Required[CumulativeGroupedBulkConfig] + """Configuration for cumulative_grouped_bulk pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_bulk"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_grouped_allocation_price.py b/src/orb/types/shared_params/new_plan_grouped_allocation_price.py new file mode 100644 index 00000000..69d606d3 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_grouped_allocation_price.py @@ -0,0 +1,113 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanGroupedAllocationPrice", "GroupedAllocationConfig", "ConversionRateConfig"] + + +class GroupedAllocationConfig(TypedDict, total=False): + """Configuration for grouped_allocation pricing""" + + allocation: Required[str] + """Usage allocation per group""" + + grouping_key: Required[str] + """How to determine the groups that should each be allocated some quantity""" + + overage_unit_rate: Required[str] + """Unit rate for post-allocation""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanGroupedAllocationPrice(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[GroupedAllocationConfig] + """Configuration for grouped_allocation pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_grouped_tiered_package_price.py b/src/orb/types/shared_params/new_plan_grouped_tiered_package_price.py new file mode 100644 index 00000000..c0ef1570 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_grouped_tiered_package_price.py @@ -0,0 +1,129 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanGroupedTieredPackagePrice", + "GroupedTieredPackageConfig", + "GroupedTieredPackageConfigTier", + "ConversionRateConfig", +] + + +class GroupedTieredPackageConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + per_unit: Required[str] + """Per package""" + + tier_lower_bound: Required[str] + + +class GroupedTieredPackageConfig(TypedDict, total=False): + """Configuration for grouped_tiered_package pricing""" + + grouping_key: Required[str] + """The event property used to group before tiering""" + + package_size: Required[str] + + tiers: Required[Iterable[GroupedTieredPackageConfigTier]] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanGroupedTieredPackagePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_tiered_package_config: Required[GroupedTieredPackageConfig] + """Configuration for grouped_tiered_package pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_tiered_package"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_grouped_tiered_price.py b/src/orb/types/shared_params/new_plan_grouped_tiered_price.py new file mode 100644 index 00000000..dbbed5b4 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_grouped_tiered_price.py @@ -0,0 +1,122 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanGroupedTieredPrice", "GroupedTieredConfig", "GroupedTieredConfigTier", "ConversionRateConfig"] + + +class GroupedTieredConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + tier_lower_bound: Required[str] + + unit_amount: Required[str] + """Per unit amount""" + + +class GroupedTieredConfig(TypedDict, total=False): + """Configuration for grouped_tiered pricing""" + + grouping_key: Required[str] + """The billable metric property used to group before tiering""" + + tiers: Required[Iterable[GroupedTieredConfigTier]] + """ + Apply tiered pricing to each segment generated after grouping with the provided + key + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanGroupedTieredPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_tiered_config: Required[GroupedTieredConfig] + """Configuration for grouped_tiered pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_tiered"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_grouped_with_metered_minimum_price.py b/src/orb/types/shared_params/new_plan_grouped_with_metered_minimum_price.py new file mode 100644 index 00000000..3d5ea79c --- /dev/null +++ b/src/orb/types/shared_params/new_plan_grouped_with_metered_minimum_price.py @@ -0,0 +1,151 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanGroupedWithMeteredMinimumPrice", + "GroupedWithMeteredMinimumConfig", + "GroupedWithMeteredMinimumConfigScalingFactor", + "GroupedWithMeteredMinimumConfigUnitAmount", + "ConversionRateConfig", +] + + +class GroupedWithMeteredMinimumConfigScalingFactor(TypedDict, total=False): + """Configuration for a scaling factor""" + + scaling_factor: Required[str] + + scaling_value: Required[str] + + +class GroupedWithMeteredMinimumConfigUnitAmount(TypedDict, total=False): + """Configuration for a unit amount""" + + pricing_value: Required[str] + + unit_amount: Required[str] + """Per unit amount""" + + +class GroupedWithMeteredMinimumConfig(TypedDict, total=False): + """Configuration for grouped_with_metered_minimum pricing""" + + grouping_key: Required[str] + """Used to partition the usage into groups. + + The minimum amount is applied to each group. + """ + + minimum_unit_amount: Required[str] + """The minimum amount to charge per group per unit""" + + pricing_key: Required[str] + """Used to determine the unit rate""" + + scaling_factors: Required[Iterable[GroupedWithMeteredMinimumConfigScalingFactor]] + """Scale the unit rates by the scaling factor.""" + + scaling_key: Required[str] + """Used to determine the unit rate scaling factor""" + + unit_amounts: Required[Iterable[GroupedWithMeteredMinimumConfigUnitAmount]] + """Apply per unit pricing to each pricing value. + + The minimum amount is applied any unmatched usage. + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanGroupedWithMeteredMinimumPrice(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[GroupedWithMeteredMinimumConfig] + """Configuration for grouped_with_metered_minimum pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_metered_minimum"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_grouped_with_prorated_minimum_price.py b/src/orb/types/shared_params/new_plan_grouped_with_prorated_minimum_price.py new file mode 100644 index 00000000..aa1e841b --- /dev/null +++ b/src/orb/types/shared_params/new_plan_grouped_with_prorated_minimum_price.py @@ -0,0 +1,113 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanGroupedWithProratedMinimumPrice", "GroupedWithProratedMinimumConfig", "ConversionRateConfig"] + + +class GroupedWithProratedMinimumConfig(TypedDict, total=False): + """Configuration for grouped_with_prorated_minimum pricing""" + + grouping_key: Required[str] + """How to determine the groups that should each have a minimum""" + + minimum: Required[str] + """The minimum amount to charge per group""" + + unit_rate: Required[str] + """The amount to charge per unit""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanGroupedWithProratedMinimumPrice(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[GroupedWithProratedMinimumConfig] + """Configuration for grouped_with_prorated_minimum pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_prorated_minimum"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_matrix_price.py b/src/orb/types/shared_params/new_plan_matrix_price.py new file mode 100644 index 00000000..fdbdd185 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_matrix_price.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .matrix_config import MatrixConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanMatrixPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanMatrixPrice(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 price will be associated with.""" + + matrix_config: Required[MatrixConfig] + """Configuration for matrix pricing""" + + model_type: Required[Literal["matrix"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_matrix_with_allocation_price.py b/src/orb/types/shared_params/new_plan_matrix_with_allocation_price.py new file mode 100644 index 00000000..4c5eb62e --- /dev/null +++ b/src/orb/types/shared_params/new_plan_matrix_with_allocation_price.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .matrix_with_allocation_config import MatrixWithAllocationConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanMatrixWithAllocationPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanMatrixWithAllocationPrice(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 price will be associated with.""" + + matrix_with_allocation_config: Required[MatrixWithAllocationConfig] + """Configuration for matrix_with_allocation pricing""" + + model_type: Required[Literal["matrix_with_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_matrix_with_display_name_price.py b/src/orb/types/shared_params/new_plan_matrix_with_display_name_price.py new file mode 100644 index 00000000..960e52f5 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_matrix_with_display_name_price.py @@ -0,0 +1,128 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanMatrixWithDisplayNamePrice", + "MatrixWithDisplayNameConfig", + "MatrixWithDisplayNameConfigUnitAmount", + "ConversionRateConfig", +] + + +class MatrixWithDisplayNameConfigUnitAmount(TypedDict, total=False): + """Configuration for a unit amount item""" + + dimension_value: Required[str] + """The dimension value""" + + display_name: Required[str] + """Display name for this dimension value""" + + unit_amount: Required[str] + """Per unit amount""" + + +class MatrixWithDisplayNameConfig(TypedDict, total=False): + """Configuration for matrix_with_display_name pricing""" + + dimension: Required[str] + """Used to determine the unit rate""" + + unit_amounts: Required[Iterable[MatrixWithDisplayNameConfigUnitAmount]] + """Apply per unit pricing to each dimension value""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanMatrixWithDisplayNamePrice(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 price will be associated with.""" + + matrix_with_display_name_config: Required[MatrixWithDisplayNameConfig] + """Configuration for matrix_with_display_name pricing""" + + model_type: Required[Literal["matrix_with_display_name"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_max_group_tiered_package_price.py b/src/orb/types/shared_params/new_plan_max_group_tiered_package_price.py new file mode 100644 index 00000000..5aa49157 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_max_group_tiered_package_price.py @@ -0,0 +1,128 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanMaxGroupTieredPackagePrice", + "MaxGroupTieredPackageConfig", + "MaxGroupTieredPackageConfigTier", + "ConversionRateConfig", +] + + +class MaxGroupTieredPackageConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + tier_lower_bound: Required[str] + + unit_amount: Required[str] + """Per unit amount""" + + +class MaxGroupTieredPackageConfig(TypedDict, total=False): + """Configuration for max_group_tiered_package pricing""" + + grouping_key: Required[str] + """ + The event property used to group before tiering the group with the highest value + """ + + package_size: Required[str] + + tiers: Required[Iterable[MaxGroupTieredPackageConfigTier]] + """Apply tiered pricing to the largest group after grouping with the provided key.""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanMaxGroupTieredPackagePrice(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 price will be associated with.""" + + max_group_tiered_package_config: Required[MaxGroupTieredPackageConfig] + """Configuration for max_group_tiered_package pricing""" + + model_type: Required[Literal["max_group_tiered_package"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_minimum_composite_price.py b/src/orb/types/shared_params/new_plan_minimum_composite_price.py new file mode 100644 index 00000000..e5e3d72f --- /dev/null +++ b/src/orb/types/shared_params/new_plan_minimum_composite_price.py @@ -0,0 +1,110 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanMinimumCompositePrice", "MinimumCompositeConfig", "ConversionRateConfig"] + + +class MinimumCompositeConfig(TypedDict, total=False): + """Configuration for minimum_composite pricing""" + + minimum_amount: Required[str] + """The minimum amount to apply""" + + prorated: bool + """If true, subtotals from this price are prorated based on the service period""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanMinimumCompositePrice(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 price will be associated with.""" + + minimum_composite_config: Required[MinimumCompositeConfig] + """Configuration for minimum_composite pricing""" + + model_type: Required[Literal["minimum_composite"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_package_price.py b/src/orb/types/shared_params/new_plan_package_price.py new file mode 100644 index 00000000..16419294 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_package_price.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .package_config import PackageConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanPackagePrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanPackagePrice(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 price will be associated with.""" + + model_type: Required[Literal["package"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + package_config: Required[PackageConfig] + """Configuration for package pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_package_with_allocation_price.py b/src/orb/types/shared_params/new_plan_package_with_allocation_price.py new file mode 100644 index 00000000..f878fae0 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_package_with_allocation_price.py @@ -0,0 +1,110 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanPackageWithAllocationPrice", "PackageWithAllocationConfig", "ConversionRateConfig"] + + +class PackageWithAllocationConfig(TypedDict, total=False): + """Configuration for package_with_allocation pricing""" + + allocation: Required[str] + + package_amount: Required[str] + + package_size: Required[str] + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanPackageWithAllocationPrice(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 price will be associated with.""" + + model_type: Required[Literal["package_with_allocation"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + package_with_allocation_config: Required[PackageWithAllocationConfig] + """Configuration for package_with_allocation pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_scalable_matrix_with_tiered_pricing_price.py b/src/orb/types/shared_params/new_plan_scalable_matrix_with_tiered_pricing_price.py new file mode 100644 index 00000000..42191033 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_scalable_matrix_with_tiered_pricing_price.py @@ -0,0 +1,139 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanScalableMatrixWithTieredPricingPrice", + "ScalableMatrixWithTieredPricingConfig", + "ScalableMatrixWithTieredPricingConfigMatrixScalingFactor", + "ScalableMatrixWithTieredPricingConfigTier", + "ConversionRateConfig", +] + + +class ScalableMatrixWithTieredPricingConfigMatrixScalingFactor(TypedDict, total=False): + """Configuration for a single matrix scaling factor""" + + first_dimension_value: Required[str] + + scaling_factor: Required[str] + + second_dimension_value: Optional[str] + + +class ScalableMatrixWithTieredPricingConfigTier(TypedDict, total=False): + """Configuration for a single tier entry with business logic""" + + tier_lower_bound: Required[str] + + unit_amount: Required[str] + + +class ScalableMatrixWithTieredPricingConfig(TypedDict, total=False): + """Configuration for scalable_matrix_with_tiered_pricing pricing""" + + first_dimension: Required[str] + """Used for the scalable matrix first dimension""" + + matrix_scaling_factors: Required[Iterable[ScalableMatrixWithTieredPricingConfigMatrixScalingFactor]] + """Apply a scaling factor to each dimension""" + + tiers: Required[Iterable[ScalableMatrixWithTieredPricingConfigTier]] + + second_dimension: Optional[str] + """Used for the scalable matrix second dimension (optional)""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanScalableMatrixWithTieredPricingPrice(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 price will be associated with.""" + + model_type: Required[Literal["scalable_matrix_with_tiered_pricing"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + scalable_matrix_with_tiered_pricing_config: Required[ScalableMatrixWithTieredPricingConfig] + """Configuration for scalable_matrix_with_tiered_pricing pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_scalable_matrix_with_unit_pricing_price.py b/src/orb/types/shared_params/new_plan_scalable_matrix_with_unit_pricing_price.py new file mode 100644 index 00000000..d2085ec1 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_scalable_matrix_with_unit_pricing_price.py @@ -0,0 +1,137 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanScalableMatrixWithUnitPricingPrice", + "ScalableMatrixWithUnitPricingConfig", + "ScalableMatrixWithUnitPricingConfigMatrixScalingFactor", + "ConversionRateConfig", +] + + +class ScalableMatrixWithUnitPricingConfigMatrixScalingFactor(TypedDict, total=False): + """Configuration for a single matrix scaling factor""" + + first_dimension_value: Required[str] + + scaling_factor: Required[str] + + second_dimension_value: Optional[str] + + +class ScalableMatrixWithUnitPricingConfig(TypedDict, total=False): + """Configuration for scalable_matrix_with_unit_pricing pricing""" + + first_dimension: Required[str] + """Used to determine the unit rate""" + + matrix_scaling_factors: Required[Iterable[ScalableMatrixWithUnitPricingConfigMatrixScalingFactor]] + """Apply a scaling factor to each dimension""" + + unit_price: Required[str] + """The final unit price to rate against the output of the matrix""" + + grouping_key: Optional[str] + """The property used to group this price""" + + prorate: Optional[bool] + """If true, the unit price will be prorated to the billing period""" + + second_dimension: Optional[str] + """Used to determine the unit rate (optional)""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanScalableMatrixWithUnitPricingPrice(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 price will be associated with.""" + + model_type: Required[Literal["scalable_matrix_with_unit_pricing"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + scalable_matrix_with_unit_pricing_config: Required[ScalableMatrixWithUnitPricingConfig] + """Configuration for scalable_matrix_with_unit_pricing pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_threshold_total_amount_price.py b/src/orb/types/shared_params/new_plan_threshold_total_amount_price.py new file mode 100644 index 00000000..86cb1ef5 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_threshold_total_amount_price.py @@ -0,0 +1,127 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanThresholdTotalAmountPrice", + "ThresholdTotalAmountConfig", + "ThresholdTotalAmountConfigConsumptionTable", + "ConversionRateConfig", +] + + +class ThresholdTotalAmountConfigConsumptionTable(TypedDict, total=False): + """Configuration for a single threshold""" + + threshold: Required[str] + + total_amount: Required[str] + """Total amount for this threshold""" + + +class ThresholdTotalAmountConfig(TypedDict, total=False): + """Configuration for threshold_total_amount pricing""" + + consumption_table: Required[Iterable[ThresholdTotalAmountConfigConsumptionTable]] + """ + When the quantity consumed passes a provided threshold, the configured total + will be charged + """ + + prorate: Optional[bool] + """If true, the unit price will be prorated to the billing period""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanThresholdTotalAmountPrice(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 price will be associated with.""" + + model_type: Required[Literal["threshold_total_amount"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + threshold_total_amount_config: Required[ThresholdTotalAmountConfig] + """Configuration for threshold_total_amount pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_tiered_package_price.py b/src/orb/types/shared_params/new_plan_tiered_package_price.py new file mode 100644 index 00000000..6c2c96db --- /dev/null +++ b/src/orb/types/shared_params/new_plan_tiered_package_price.py @@ -0,0 +1,123 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanTieredPackagePrice", "TieredPackageConfig", "TieredPackageConfigTier", "ConversionRateConfig"] + + +class TieredPackageConfigTier(TypedDict, total=False): + """Configuration for a single tier with business logic""" + + per_unit: Required[str] + """Price per package""" + + tier_lower_bound: Required[str] + + +class TieredPackageConfig(TypedDict, total=False): + """Configuration for tiered_package pricing""" + + package_size: Required[str] + + tiers: Required[Iterable[TieredPackageConfigTier]] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. The tier bounds are defined + based on the total quantity rather than the number of packages, so they must be + multiples of the package size. + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanTieredPackagePrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered_package"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_package_config: Required[TieredPackageConfig] + """Configuration for tiered_package pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_tiered_package_with_minimum_price.py b/src/orb/types/shared_params/new_plan_tiered_package_with_minimum_price.py new file mode 100644 index 00000000..cdb4b2e3 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_tiered_package_with_minimum_price.py @@ -0,0 +1,127 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanTieredPackageWithMinimumPrice", + "TieredPackageWithMinimumConfig", + "TieredPackageWithMinimumConfigTier", + "ConversionRateConfig", +] + + +class TieredPackageWithMinimumConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + minimum_amount: Required[str] + + per_unit: Required[str] + + tier_lower_bound: Required[str] + + +class TieredPackageWithMinimumConfig(TypedDict, total=False): + """Configuration for tiered_package_with_minimum pricing""" + + package_size: Required[float] + + tiers: Required[Iterable[TieredPackageWithMinimumConfigTier]] + """Apply tiered pricing after rounding up the quantity to the package size. + + Tiers are defined using exclusive lower bounds. + """ + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanTieredPackageWithMinimumPrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered_package_with_minimum"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_package_with_minimum_config: Required[TieredPackageWithMinimumConfig] + """Configuration for tiered_package_with_minimum pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_tiered_price.py b/src/orb/types/shared_params/new_plan_tiered_price.py new file mode 100644 index 00000000..e1d026d0 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_tiered_price.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .tiered_config import TieredConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanTieredPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanTieredPrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_config: Required[TieredConfig] + """Configuration for tiered pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_tiered_with_minimum_price.py b/src/orb/types/shared_params/new_plan_tiered_with_minimum_price.py new file mode 100644 index 00000000..0a107b71 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_tiered_with_minimum_price.py @@ -0,0 +1,132 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = [ + "NewPlanTieredWithMinimumPrice", + "TieredWithMinimumConfig", + "TieredWithMinimumConfigTier", + "ConversionRateConfig", +] + + +class TieredWithMinimumConfigTier(TypedDict, total=False): + """Configuration for a single tier""" + + minimum_amount: Required[str] + + tier_lower_bound: Required[str] + + unit_amount: Required[str] + """Per unit amount""" + + +class TieredWithMinimumConfig(TypedDict, total=False): + """Configuration for tiered_with_minimum pricing""" + + tiers: Required[Iterable[TieredWithMinimumConfigTier]] + """Tiered pricing with a minimum amount dependent on the volume tier. + + Tiers are defined using exclusive lower bounds. + """ + + hide_zero_amount_tiers: bool + """If true, tiers with an accrued amount of 0 will not be included in the rating.""" + + prorate: bool + """If true, the unit price will be prorated to the billing period""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanTieredWithMinimumPrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered_with_minimum"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_with_minimum_config: Required[TieredWithMinimumConfig] + """Configuration for tiered_with_minimum pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_unit_price.py b/src/orb/types/shared_params/new_plan_unit_price.py new file mode 100644 index 00000000..bfc4a50d --- /dev/null +++ b/src/orb/types/shared_params/new_plan_unit_price.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_config import UnitConfig +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanUnitPrice", "ConversionRateConfig"] + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanUnitPrice(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 price will be associated with.""" + + model_type: Required[Literal["unit"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_config: Required[UnitConfig] + """Configuration for unit pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_unit_with_percent_price.py b/src/orb/types/shared_params/new_plan_unit_with_percent_price.py new file mode 100644 index 00000000..dbc8ed1d --- /dev/null +++ b/src/orb/types/shared_params/new_plan_unit_with_percent_price.py @@ -0,0 +1,110 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanUnitWithPercentPrice", "UnitWithPercentConfig", "ConversionRateConfig"] + + +class UnitWithPercentConfig(TypedDict, total=False): + """Configuration for unit_with_percent pricing""" + + percent: Required[str] + """What percent, out of 100, of the calculated total to charge""" + + unit_amount: Required[str] + """Rate per unit of usage""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanUnitWithPercentPrice(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 price will be associated with.""" + + model_type: Required[Literal["unit_with_percent"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_with_percent_config: Required[UnitWithPercentConfig] + """Configuration for unit_with_percent pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_plan_unit_with_proration_price.py b/src/orb/types/shared_params/new_plan_unit_with_proration_price.py new file mode 100644 index 00000000..cd8ee561 --- /dev/null +++ b/src/orb/types/shared_params/new_plan_unit_with_proration_price.py @@ -0,0 +1,107 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .unit_conversion_rate_config import UnitConversionRateConfig +from .tiered_conversion_rate_config import TieredConversionRateConfig +from .new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_dimensional_price_configuration import NewDimensionalPriceConfiguration + +__all__ = ["NewPlanUnitWithProrationPrice", "UnitWithProrationConfig", "ConversionRateConfig"] + + +class UnitWithProrationConfig(TypedDict, total=False): + """Configuration for unit_with_proration pricing""" + + unit_amount: Required[str] + """Rate per unit of usage""" + + +ConversionRateConfig: TypeAlias = Union[UnitConversionRateConfig, TieredConversionRateConfig] + + +class NewPlanUnitWithProrationPrice(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 price will be associated with.""" + + model_type: Required[Literal["unit_with_proration"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + unit_with_proration_config: Required[UnitWithProrationConfig] + """Configuration for unit_with_proration pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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. + """ diff --git a/src/orb/types/shared_params/new_usage_discount.py b/src/orb/types/shared_params/new_usage_discount.py new file mode 100644 index 00000000..7f285264 --- /dev/null +++ b/src/orb/types/shared_params/new_usage_discount.py @@ -0,0 +1,51 @@ +# 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 + +from ..._types import SequenceNotStr + +__all__ = ["NewUsageDiscount", "Filter"] + + +class Filter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class NewUsageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["usage_discount"]] + + usage_discount: Required[float] + + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[Iterable[Filter]] + """A list of filters that determine which prices this adjustment will apply to.""" + + 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. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" diff --git a/src/orb/types/shared_params/package_config.py b/src/orb/types/shared_params/package_config.py new file mode 100644 index 00000000..f37339fd --- /dev/null +++ b/src/orb/types/shared_params/package_config.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["PackageConfig"] + + +class PackageConfig(TypedDict, total=False): + """Configuration for package pricing""" + + 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 + """ 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..bdd842fb --- /dev/null +++ b/src/orb/types/shared_params/percentage_discount.py @@ -0,0 +1,42 @@ +# 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 + +from ..._types import SequenceNotStr + +__all__ = ["PercentageDiscount", "Filter"] + + +class Filter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class PercentageDiscount(TypedDict, total=False): + discount_type: Required[Literal["percentage"]] + + percentage_discount: Required[float] + """Only available if discount_type is `percentage`. + + This is a number between 0 and 1. + """ + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + filters: Optional[Iterable[Filter]] + """The filters that determine which prices to apply this discount to.""" + + reason: Optional[str] diff --git a/src/orb/types/shared_params/tier.py b/src/orb/types/shared_params/tier.py new file mode 100644 index 00000000..cf66df3c --- /dev/null +++ b/src/orb/types/shared_params/tier.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +__all__ = ["Tier"] + + +class Tier(TypedDict, total=False): + """Configuration for a single tier""" + + first_unit: Required[float] + """Exclusive tier starting value""" + + unit_amount: Required[str] + """Amount per unit""" + + last_unit: Optional[float] + """Inclusive tier ending value. + + This value is null if and only if this is the last tier. + """ diff --git a/src/orb/types/shared_params/tiered_config.py b/src/orb/types/shared_params/tiered_config.py new file mode 100644 index 00000000..31c9dc11 --- /dev/null +++ b/src/orb/types/shared_params/tiered_config.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +from .tier import Tier + +__all__ = ["TieredConfig"] + + +class TieredConfig(TypedDict, total=False): + """Configuration for tiered pricing""" + + tiers: Required[Iterable[Tier]] + """Tiers for rating based on total usage quantities into the specified tier""" + + prorated: bool + """If true, subtotals from this price are prorated based on the service period""" diff --git a/src/orb/types/shared_params/tiered_conversion_rate_config.py b/src/orb/types/shared_params/tiered_conversion_rate_config.py new file mode 100644 index 00000000..23775799 --- /dev/null +++ b/src/orb/types/shared_params/tiered_conversion_rate_config.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from .conversion_rate_tiered_config import ConversionRateTieredConfig + +__all__ = ["TieredConversionRateConfig"] + + +class TieredConversionRateConfig(TypedDict, total=False): + conversion_rate_type: Required[Literal["tiered"]] + + tiered_config: Required[ConversionRateTieredConfig] 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..f2af6d5d --- /dev/null +++ b/src/orb/types/shared_params/trial_discount.py @@ -0,0 +1,42 @@ +# 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 + +from ..._types import SequenceNotStr + +__all__ = ["TrialDiscount", "Filter"] + + +class Filter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class TrialDiscount(TypedDict, total=False): + discount_type: Required[Literal["trial"]] + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + filters: Optional[Iterable[Filter]] + """The filters that determine which prices to apply this discount to.""" + + 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/shared_params/unit_config.py b/src/orb/types/shared_params/unit_config.py new file mode 100644 index 00000000..ed96da86 --- /dev/null +++ b/src/orb/types/shared_params/unit_config.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["UnitConfig"] + + +class UnitConfig(TypedDict, total=False): + """Configuration for unit pricing""" + + unit_amount: Required[str] + """Rate per unit of usage""" + + prorated: bool + """If true, subtotals from this price are prorated based on the service period""" diff --git a/src/orb/types/shared_params/unit_conversion_rate_config.py b/src/orb/types/shared_params/unit_conversion_rate_config.py new file mode 100644 index 00000000..9798904b --- /dev/null +++ b/src/orb/types/shared_params/unit_conversion_rate_config.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from .conversion_rate_unit_config import ConversionRateUnitConfig + +__all__ = ["UnitConversionRateConfig"] + + +class UnitConversionRateConfig(TypedDict, total=False): + conversion_rate_type: Required[Literal["unit"]] + + unit_config: Required[ConversionRateUnitConfig] diff --git a/src/orb/types/shared_params/usage_discount.py b/src/orb/types/shared_params/usage_discount.py new file mode 100644 index 00000000..d26dcbc6 --- /dev/null +++ b/src/orb/types/shared_params/usage_discount.py @@ -0,0 +1,42 @@ +# 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 + +from ..._types import SequenceNotStr + +__all__ = ["UsageDiscount", "Filter"] + + +class Filter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class UsageDiscount(TypedDict, total=False): + discount_type: Required[Literal["usage"]] + + usage_discount: Required[float] + """Only available if discount_type is `usage`. + + Number of usage units that this discount is for + """ + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + filters: Optional[Iterable[Filter]] + """The filters that determine which prices to apply this discount to.""" + + reason: Optional[str] diff --git a/src/orb/types/subscription.py b/src/orb/types/subscription.py index f0ca54b4..2b4fbd74 100644 --- a/src/orb/types/subscription.py +++ b/src/orb/types/subscription.py @@ -2,459 +2,150 @@ from typing import Dict, List, Union, Optional from datetime import datetime -from typing_extensions import Literal +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 +from .shared.price_interval import PriceInterval +from .shared.maximum_interval import MaximumInterval +from .shared.minimum_interval import MinimumInterval +from .shared.coupon_redemption import CouponRedemption +from .shared.adjustment_interval import AdjustmentInterval +from .shared.subscription_trial_info import SubscriptionTrialInfo +from .shared.usage_discount_interval import UsageDiscountInterval +from .shared.amount_discount_interval import AmountDiscountInterval +from .shared.percentage_discount_interval import PercentageDiscountInterval +from .shared.subscription_change_minified import SubscriptionChangeMinified +from .shared.fixed_fee_quantity_schedule_entry import FixedFeeQuantityScheduleEntry +from .shared.billing_cycle_anchor_configuration import BillingCycleAnchorConfiguration __all__ = [ "Subscription", "DiscountInterval", - "DiscountIntervalAmountDiscountInterval", - "DiscountIntervalPercentageDiscountInterval", - "DiscountIntervalUsageDiscountInterval", - "FixedFeeQuantitySchedule", - "MaximumInterval", - "MinimumInterval", - "PriceInterval", - "PriceIntervalFixedFeeQuantityTransition", - "RedeemedCoupon", - "TrialInfo", + "DiscountIntervalTieredPercentageDiscountInterval", + "DiscountIntervalTieredPercentageDiscountIntervalFilter", + "DiscountIntervalTieredPercentageDiscountIntervalTier", ] -class DiscountIntervalAmountDiscountInterval(BaseModel): - amount_discount: str - """Only available if discount_type is `amount`.""" +class DiscountIntervalTieredPercentageDiscountIntervalFilter(BaseModel): + field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"] + """The property of the price to filter on.""" - applies_to_price_ids: List[str] - """The price ids that this discount interval applies to.""" + operator: Literal["includes", "excludes"] + """Should prices that match the filter be included or excluded.""" - applies_to_price_interval_ids: List[str] - """The price interval ids that this discount interval applies to.""" + values: List[str] + """The IDs or values that match this filter.""" - 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 DiscountIntervalTieredPercentageDiscountIntervalTier(BaseModel): + """One band of a tiered percentage discount. + Bounds are denominated in the discount's currency. + `lower_bound` is the exclusive start of the band and `upper_bound` is the inclusive end; + `upper_bound` is null only for the open-ended final tier. + """ -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.""" + lower_bound: float + """Exclusive lower bound of cumulative spend for this tier.""" - percentage_discount: float + percentage: float """ - Only available if discount_type is `percentage`.This is a number between 0 - and 1. + The percentage (between 0 and 1) discounted from spend that falls within this + tier. """ - start_date: datetime - """The start date of the discount interval.""" - + upper_bound: Optional[float] = None + """ + Inclusive upper bound of cumulative spend for this tier; null for the final + open-ended tier. + """ -class DiscountIntervalUsageDiscountInterval(BaseModel): - applies_to_price_ids: List[str] - """The price ids that this discount interval applies to.""" +class DiscountIntervalTieredPercentageDiscountInterval(BaseModel): applies_to_price_interval_ids: List[str] """The price interval ids that this discount interval applies to.""" - discount_type: Literal["usage"] + discount_type: Literal["tiered_percentage"] end_date: Optional[datetime] = None """The end date of the discount interval.""" + filters: List[DiscountIntervalTieredPercentageDiscountIntervalFilter] + """The filters that determine which prices this discount interval applies to.""" + start_date: datetime """The start date of the discount interval.""" - usage_discount: float - """Only available if discount_type is `usage`. + tiers: List[DiscountIntervalTieredPercentageDiscountIntervalTier] + """Only available if discount_type is `tiered_percentage`. - Number of usage units that this discount is for + The ordered, contiguous bands of cumulative eligible spend, each discounted at + its own percentage. """ -DiscountInterval = Union[ - DiscountIntervalAmountDiscountInterval, - DiscountIntervalPercentageDiscountInterval, - DiscountIntervalUsageDiscountInterval, +DiscountInterval: TypeAlias = Annotated[ + Union[ + AmountDiscountInterval, + PercentageDiscountInterval, + UsageDiscountInterval, + DiscountIntervalTieredPercentageDiscountInterval, + ], + 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. +class Subscription(BaseModel): """ + A [subscription](/core-concepts#subscription) represents the purchase of a plan by a customer. - 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.""" + By default, subscriptions begin on the day that they're created and renew automatically for each billing cycle at + the cadence that's configured in the plan definition. - applies_to_price_interval_ids: List[str] - """The price interval ids that this minimum interval applies to.""" + Subscriptions also default to **beginning of month alignment**, which means the first invoice issued for the + subscription will have pro-rated charges between the `start_date` and the first of the following month. Subsequent + billing periods will always start and end on a month boundary (e.g. subsequent month starts for monthly billing). - 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. + Depending on the plan configuration, any _flat_ recurring fees will be billed either at the beginning (in-advance) + or end (in-arrears) of each billing cycle. Plans default to **in-advance billing**. Usage-based fees are billed in + arrears as usage is accumulated. In the normal course of events, you can expect an invoice to contain usage-based + charges for the previous period, and a recurring fee for the following period. """ - 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. + active_plan_phase_order: Optional[int] = None """ - - 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. + The current plan phase that is active, only if the subscription's plan has + phases. """ - end_date: Optional[datetime] = None - """The end date of the price interval. - - This is the date that Orb stops billing for this price. + adjustment_intervals: List[AdjustmentInterval] """ - - fixed_fee_quantity_transitions: Optional[List[PriceIntervalFixedFeeQuantityTransition]] = None - """The fixed fee quantity transitions for this price interval. - - This is only relevant for fixed fees. + The adjustment intervals for this subscription sorted by the start_date of the + adjustment interval. """ - price: Price + auto_collection: Optional[bool] = None """ - 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 - ... - } - ``` + 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. """ - start_date: datetime - """The start date of the price interval. + auto_issuance: Optional[bool] = None + """Determines whether invoices for this subscription will be automatically issued. - This is the date that Orb starts billing for this price. + This resolves the effective setting for the subscription: a subscription-level + override if set, otherwise the customer-level setting, otherwise the + account-level default. """ - -class RedeemedCoupon(BaseModel): - coupon_id: str - - end_date: Optional[datetime] = None - - start_date: datetime - - -class TrialInfo(BaseModel): - end_date: Optional[datetime] = None - - -class Subscription(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. - """ - - 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. - """ + billing_cycle_anchor_configuration: BillingCycleAnchorConfiguration billing_cycle_day: int """The day of the month on which the billing cycle is anchored. @@ -489,7 +180,7 @@ class Subscription(BaseModel): 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 + [Customer ID Aliases](/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 @@ -498,9 +189,8 @@ class Subscription(BaseModel): 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. + your account's timezone. See [Timezone localization](/essentials/timezones) for + information on what this timezone parameter influences within Orb. """ default_invoice_memo: Optional[str] = None @@ -510,17 +200,23 @@ class Subscription(BaseModel): """ discount_intervals: List[DiscountInterval] - """The discount intervals for this subscription.""" + """The discount intervals for this subscription sorted by the start_date. + + This field is deprecated in favor of `adjustment_intervals`. + """ end_date: Optional[datetime] = None """The date Orb stops billing for this subscription.""" - fixed_fee_quantity_schedule: List[FixedFeeQuantitySchedule] + fixed_fee_quantity_schedule: List[FixedFeeQuantityScheduleEntry] invoicing_threshold: Optional[str] = None maximum_intervals: List[MaximumInterval] - """The maximum intervals for this subscription.""" + """The maximum intervals for this subscription sorted by the start_date. + + This field is deprecated in favor of `adjustment_intervals`. + """ metadata: Dict[str, str] """User specified key-value pairs for the resource. @@ -531,7 +227,13 @@ class Subscription(BaseModel): """ minimum_intervals: List[MinimumInterval] - """The minimum intervals for this subscription.""" + """The minimum intervals for this subscription sorted by the start_date. + + This field is deprecated in favor of `adjustment_intervals`. + """ + + name: str + """The name of the subscription.""" net_terms: int """ @@ -541,22 +243,25 @@ class Subscription(BaseModel): has a month to pay the invoice. """ - plan: Plan + pending_subscription_change: Optional[SubscriptionChangeMinified] = None + """A pending subscription change if one exists on this subscription.""" + + plan: Optional[Plan] = None """ - 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 + The [Plan](/core-concepts#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 + redeemed_coupon: Optional[CouponRedemption] = None start_date: datetime """The date Orb starts billing for this subscription.""" status: Literal["active", "ended", "upcoming"] - trial_info: TrialInfo + trial_info: SubscriptionTrialInfo diff --git a/src/orb/types/subscription_cancel_params.py b/src/orb/types/subscription_cancel_params.py index 6ce855b1..adb583e4 100644 --- a/src/orb/types/subscription_cancel_params.py +++ b/src/orb/types/subscription_cancel_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union +from typing import Union, Optional from datetime import datetime from typing_extensions import Literal, Required, Annotated, TypedDict @@ -15,6 +15,13 @@ class SubscriptionCancelParams(TypedDict, total=False): cancel_option: Required[Literal["end_of_subscription_term", "immediate", "requested_date"]] """Determines the timing of subscription cancellation""" + allow_invoice_credit_or_void: Optional[bool] + """ + If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + """ + cancellation_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] """The date that the cancellation should take effect. diff --git a/src/orb/types/subscription_change_apply_params.py b/src/orb/types/subscription_change_apply_params.py new file mode 100644 index 00000000..21142c0c --- /dev/null +++ b/src/orb/types/subscription_change_apply_params.py @@ -0,0 +1,46 @@ +# 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 date +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["SubscriptionChangeApplyParams"] + + +class SubscriptionChangeApplyParams(TypedDict, total=False): + description: Optional[str] + """Description to apply to the balance transaction representing this credit.""" + + mark_as_paid: Optional[bool] + """Mark all pending invoices that are payable as paid. + + If amount is also provided, mark as paid and credit the difference to the + customer's balance. + """ + + payment_external_id: Optional[str] + """An optional external ID to associate with the payment. + + Only applicable when mark_as_paid is true. + """ + + payment_notes: Optional[str] + """Optional notes about the payment. Only applicable when mark_as_paid is true.""" + + payment_received_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """A date string to specify the date the payment was received. + + Only applicable when mark_as_paid is true. If not provided, defaults to the + current date. + """ + + previously_collected_amount: Optional[str] + """Amount already collected to apply to the customer's balance. + + If mark_as_paid is also provided, credit the difference to the customer's + balance. + """ diff --git a/src/orb/types/subscription_change_apply_response.py b/src/orb/types/subscription_change_apply_response.py new file mode 100644 index 00000000..5670c50c --- /dev/null +++ b/src/orb/types/subscription_change_apply_response.py @@ -0,0 +1,53 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel +from .mutated_subscription import MutatedSubscription + +__all__ = ["SubscriptionChangeApplyResponse"] + + +class SubscriptionChangeApplyResponse(BaseModel): + """ + A subscription change represents a desired new subscription / pending change to an existing subscription. It + is a way to first preview the effects on the subscription as well as any changes/creation of invoices + (see `subscription.changed_resources`). + """ + + id: str + + change_type: str + """The type of change (e.g., 'schedule_plan_change', 'create_subscription').""" + + expiration_time: datetime + """ + Subscription change will be cancelled at this time and can no longer be applied. + """ + + status: Literal["pending", "applied", "cancelled"] + + subscription: Optional[MutatedSubscription] = None + + applied_at: Optional[datetime] = None + """When this change was applied.""" + + billing_cycle_alignment: Optional[str] = None + """Billing cycle alignment for plan changes.""" + + cancelled_at: Optional[datetime] = None + """When this change was cancelled.""" + + change_option: Optional[str] = None + """ + How the change is scheduled (e.g., 'immediate', 'end_of_subscription_term', + 'requested_date'). + """ + + effective_date: Optional[datetime] = None + """When this change will take effect.""" + + plan_id: Optional[str] = None + """The target plan ID for plan changes.""" diff --git a/src/orb/types/subscription_change_cancel_response.py b/src/orb/types/subscription_change_cancel_response.py new file mode 100644 index 00000000..996fa3c0 --- /dev/null +++ b/src/orb/types/subscription_change_cancel_response.py @@ -0,0 +1,53 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel +from .mutated_subscription import MutatedSubscription + +__all__ = ["SubscriptionChangeCancelResponse"] + + +class SubscriptionChangeCancelResponse(BaseModel): + """ + A subscription change represents a desired new subscription / pending change to an existing subscription. It + is a way to first preview the effects on the subscription as well as any changes/creation of invoices + (see `subscription.changed_resources`). + """ + + id: str + + change_type: str + """The type of change (e.g., 'schedule_plan_change', 'create_subscription').""" + + expiration_time: datetime + """ + Subscription change will be cancelled at this time and can no longer be applied. + """ + + status: Literal["pending", "applied", "cancelled"] + + subscription: Optional[MutatedSubscription] = None + + applied_at: Optional[datetime] = None + """When this change was applied.""" + + billing_cycle_alignment: Optional[str] = None + """Billing cycle alignment for plan changes.""" + + cancelled_at: Optional[datetime] = None + """When this change was cancelled.""" + + change_option: Optional[str] = None + """ + How the change is scheduled (e.g., 'immediate', 'end_of_subscription_term', + 'requested_date'). + """ + + effective_date: Optional[datetime] = None + """When this change will take effect.""" + + plan_id: Optional[str] = None + """The target plan ID for plan changes.""" diff --git a/src/orb/types/subscription_change_list_params.py b/src/orb/types/subscription_change_list_params.py new file mode 100644 index 00000000..3d52e7ab --- /dev/null +++ b/src/orb/types/subscription_change_list_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 Optional +from typing_extensions import Literal, TypedDict + +__all__ = ["SubscriptionChangeListParams"] + + +class SubscriptionChangeListParams(TypedDict, total=False): + cursor: Optional[str] + """Cursor for pagination. + + This can be populated by the `next_cursor` value returned from the initial + request. + """ + + customer_id: Optional[str] + + external_customer_id: Optional[str] + + limit: int + """The number of items to fetch. Defaults to 20.""" + + status: Optional[Literal["pending", "applied", "cancelled"]] diff --git a/src/orb/types/subscription_change_list_response.py b/src/orb/types/subscription_change_list_response.py new file mode 100644 index 00000000..1a706ddf --- /dev/null +++ b/src/orb/types/subscription_change_list_response.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["SubscriptionChangeListResponse"] + + +class SubscriptionChangeListResponse(BaseModel): + id: str + + expiration_time: datetime + """ + Subscription change will be cancelled at this time and can no longer be applied. + """ + + status: Literal["pending", "applied", "cancelled"] + + subscription_id: Optional[str] = None + + applied_at: Optional[datetime] = None + """When this change was applied.""" + + cancelled_at: Optional[datetime] = None + """When this change was cancelled.""" diff --git a/src/orb/types/subscription_change_retrieve_response.py b/src/orb/types/subscription_change_retrieve_response.py new file mode 100644 index 00000000..2cd2a723 --- /dev/null +++ b/src/orb/types/subscription_change_retrieve_response.py @@ -0,0 +1,53 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel +from .mutated_subscription import MutatedSubscription + +__all__ = ["SubscriptionChangeRetrieveResponse"] + + +class SubscriptionChangeRetrieveResponse(BaseModel): + """ + A subscription change represents a desired new subscription / pending change to an existing subscription. It + is a way to first preview the effects on the subscription as well as any changes/creation of invoices + (see `subscription.changed_resources`). + """ + + id: str + + change_type: str + """The type of change (e.g., 'schedule_plan_change', 'create_subscription').""" + + expiration_time: datetime + """ + Subscription change will be cancelled at this time and can no longer be applied. + """ + + status: Literal["pending", "applied", "cancelled"] + + subscription: Optional[MutatedSubscription] = None + + applied_at: Optional[datetime] = None + """When this change was applied.""" + + billing_cycle_alignment: Optional[str] = None + """Billing cycle alignment for plan changes.""" + + cancelled_at: Optional[datetime] = None + """When this change was cancelled.""" + + change_option: Optional[str] = None + """ + How the change is scheduled (e.g., 'immediate', 'end_of_subscription_term', + 'requested_date'). + """ + + effective_date: Optional[datetime] = None + """When this change will take effect.""" + + plan_id: Optional[str] = None + """The target plan ID for plan changes.""" diff --git a/src/orb/types/subscription_create_params.py b/src/orb/types/subscription_create_params.py index 41637c50..51fe63fe 100644 --- a/src/orb/types/subscription_create_params.py +++ b/src/orb/types/subscription_create_params.py @@ -2,71 +2,205 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict +from .._types import SequenceNotStr from .._utils import PropertyInfo +from .discount_override_param import DiscountOverrideParam +from .shared_params.new_maximum import NewMaximum +from .shared_params.new_minimum import NewMinimum +from .shared_params.new_usage_discount import NewUsageDiscount +from .new_subscription_bulk_price_param import NewSubscriptionBulkPriceParam +from .new_subscription_unit_price_param import NewSubscriptionUnitPriceParam +from .shared_params.new_amount_discount import NewAmountDiscount +from .shared_params.new_allocation_price import NewAllocationPrice +from .new_subscription_matrix_price_param import NewSubscriptionMatrixPriceParam +from .new_subscription_tiered_price_param import NewSubscriptionTieredPriceParam +from .new_subscription_package_price_param import NewSubscriptionPackagePriceParam +from .shared_params.new_percentage_discount import NewPercentageDiscount +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .new_subscription_grouped_tiered_price_param import NewSubscriptionGroupedTieredPriceParam +from .new_subscription_tiered_package_price_param import NewSubscriptionTieredPackagePriceParam +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_subscription_minimum_composite_price_param import NewSubscriptionMinimumCompositePriceParam +from .new_subscription_unit_with_percent_price_param import NewSubscriptionUnitWithPercentPriceParam +from .new_subscription_grouped_allocation_price_param import NewSubscriptionGroupedAllocationPriceParam +from .new_subscription_bulk_with_proration_price_param import NewSubscriptionBulkWithProrationPriceParam +from .new_subscription_tiered_with_minimum_price_param import NewSubscriptionTieredWithMinimumPriceParam +from .new_subscription_unit_with_proration_price_param import NewSubscriptionUnitWithProrationPriceParam +from .shared_params.billing_cycle_anchor_configuration import BillingCycleAnchorConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration +from .new_subscription_grouped_tiered_package_price_param import NewSubscriptionGroupedTieredPackagePriceParam +from .new_subscription_matrix_with_allocation_price_param import NewSubscriptionMatrixWithAllocationPriceParam +from .new_subscription_threshold_total_amount_price_param import NewSubscriptionThresholdTotalAmountPriceParam +from .new_subscription_cumulative_grouped_bulk_price_param import NewSubscriptionCumulativeGroupedBulkPriceParam +from .new_subscription_package_with_allocation_price_param import NewSubscriptionPackageWithAllocationPriceParam +from .new_subscription_matrix_with_display_name_price_param import NewSubscriptionMatrixWithDisplayNamePriceParam +from .new_subscription_max_group_tiered_package_price_param import NewSubscriptionMaxGroupTieredPackagePriceParam +from .new_subscription_tiered_package_with_minimum_price_param import NewSubscriptionTieredPackageWithMinimumPriceParam +from .new_subscription_grouped_with_metered_minimum_price_param import ( + NewSubscriptionGroupedWithMeteredMinimumPriceParam, +) +from .new_subscription_grouped_with_prorated_minimum_price_param import ( + NewSubscriptionGroupedWithProratedMinimumPriceParam, +) +from .new_subscription_scalable_matrix_with_unit_pricing_price_param import ( + NewSubscriptionScalableMatrixWithUnitPricingPriceParam, +) +from .new_subscription_scalable_matrix_with_tiered_pricing_price_param import ( + NewSubscriptionScalableMatrixWithTieredPricingPriceParam, +) __all__ = [ "SubscriptionCreateParams", - "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", + "AddAdjustment", + "AddAdjustmentAdjustment", + "AddAdjustmentAdjustmentNewTieredPercentageDiscount", + "AddAdjustmentAdjustmentNewTieredPercentageDiscountTier", + "AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter", + "AddPrice", + "AddPricePrice", + "AddPricePriceNewSubscriptionBulkWithFiltersPrice", + "AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfig", + "AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigFilter", + "AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigTier", + "AddPricePriceNewSubscriptionBulkWithFiltersPriceConversionRateConfig", + "AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPrice", + "AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig", + "AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue", + "AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup", + "AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceConversionRateConfig", + "AddPricePriceNewSubscriptionTieredWithProrationPrice", + "AddPricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfig", + "AddPricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfigTier", + "AddPricePriceNewSubscriptionTieredWithProrationPriceConversionRateConfig", + "AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPrice", + "AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig", + "AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceConversionRateConfig", + "AddPricePriceNewSubscriptionCumulativeGroupedAllocationPrice", + "AddPricePriceNewSubscriptionCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig", + "AddPricePriceNewSubscriptionCumulativeGroupedAllocationPriceConversionRateConfig", + "AddPricePriceNewSubscriptionDailyCreditAllowancePrice", + "AddPricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfig", + "AddPricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue", + "AddPricePriceNewSubscriptionDailyCreditAllowancePriceConversionRateConfig", + "AddPricePriceNewSubscriptionMeteredAllowancePrice", + "AddPricePriceNewSubscriptionMeteredAllowancePriceMeteredAllowanceConfig", + "AddPricePriceNewSubscriptionMeteredAllowancePriceConversionRateConfig", + "AddPricePriceNewSubscriptionPercentCompositePrice", + "AddPricePriceNewSubscriptionPercentCompositePricePercentConfig", + "AddPricePriceNewSubscriptionPercentCompositePriceConversionRateConfig", + "AddPricePriceNewSubscriptionEventOutputPrice", + "AddPricePriceNewSubscriptionEventOutputPriceEventOutputConfig", + "AddPricePriceNewSubscriptionEventOutputPriceConversionRateConfig", + "RemoveAdjustment", + "RemovePrice", + "ReplaceAdjustment", + "ReplaceAdjustmentAdjustment", + "ReplaceAdjustmentAdjustmentNewTieredPercentageDiscount", + "ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountTier", + "ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountFilter", + "ReplacePrice", + "ReplacePricePrice", + "ReplacePricePriceNewSubscriptionBulkWithFiltersPrice", + "ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfig", + "ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigFilter", + "ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigTier", + "ReplacePricePriceNewSubscriptionBulkWithFiltersPriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPrice", + "ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig", + "ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue", + "ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup", + "ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionTieredWithProrationPrice", + "ReplacePricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfig", + "ReplacePricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfigTier", + "ReplacePricePriceNewSubscriptionTieredWithProrationPriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPrice", + "ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig", + "ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPrice", + "ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig", + "ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionDailyCreditAllowancePrice", + "ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfig", + "ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue", + "ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionMeteredAllowancePrice", + "ReplacePricePriceNewSubscriptionMeteredAllowancePriceMeteredAllowanceConfig", + "ReplacePricePriceNewSubscriptionMeteredAllowancePriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionPercentCompositePrice", + "ReplacePricePriceNewSubscriptionPercentCompositePricePercentConfig", + "ReplacePricePriceNewSubscriptionPercentCompositePriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionEventOutputPrice", + "ReplacePricePriceNewSubscriptionEventOutputPriceEventOutputConfig", + "ReplacePricePriceNewSubscriptionEventOutputPriceConversionRateConfig", ] 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] + """ + 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. + """ + + auto_issuance: Optional[bool] + """Used to determine if invoices for this subscription will be automatically + issued. + + If true, invoices will be automatically issued. If false, invoices will require + manual approval. If `null` is specified, this defaults to the behavior + configured for this customer. + """ aws_region: Optional[str] + billing_cycle_anchor_configuration: Optional[BillingCycleAnchorConfiguration] + coupon_redemption_code: Optional[str] + """Redemption code to be used for this subscription. + + If the coupon cannot be found by its redemption code, or cannot be redeemed, an + error response will be returned and the subscription creation or plan change + will not be scheduled. + """ credits_overage_rate: Optional[float] + currency: Optional[str] + """The currency to use for the subscription. + + If not specified, the invoicing currency for the plan will be used. + """ + customer_id: Optional[str] default_invoice_memo: Optional[str] + """Determines the default memo on this subscription's invoices. + + Note that if this is not provided, it is determined by the plan configuration. + """ end_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] @@ -82,9 +216,23 @@ 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](/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""" invoicing_threshold: Optional[str] + """ + When this subscription's accrued usage reaches this threshold, an invoice will + be issued for the subscription. If not specified, invoices will only be issued + at the end of the billing period. + """ metadata: Optional[Dict[str, Optional[str]]] """User-specified key/value pairs for the resource. @@ -93,9 +241,20 @@ class SubscriptionCreateParams(TypedDict, total=False): metadata mapping can be cleared by setting `metadata` to `null`. """ + name: Optional[str] + """The name to use for the subscription. + + If not specified, the plan name will be used. + """ + net_terms: Optional[int] + """ + The net terms determines the difference between the invoice date and the issue + date for the invoice. If you intend the invoice to be due on issue, set this + to 0. If not provided, this defaults to the value specified in the plan. + """ - per_credit_overage_amount: Optional[str] + per_credit_overage_amount: Optional[float] plan_id: Optional[str] """The plan that the given subscription should be switched to. @@ -103,766 +262,2555 @@ class SubscriptionCreateParams(TypedDict, total=False): Note that either this property or `external_plan_id` must be specified. """ - price_overrides: Optional[Iterable[PriceOverride]] - """Optionally provide a list of overrides for prices on the plan""" + plan_version_number: Optional[int] + """Specifies which version of the plan to subscribe to. - start_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + If null, the default version will be used. + """ + price_overrides: Optional[Iterable[object]] + """Optionally provide a list of overrides for prices on the plan""" -class PriceOverrideOverrideUnitPriceUnitConfig(TypedDict, total=False): - unit_amount: Required[str] - """Rate per unit of usage""" + 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) + """ -class PriceOverrideOverrideUnitPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + remove_prices: Optional[Iterable[RemovePrice]] + """Plan prices to be removed from the subscription. - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + (Only available for accounts that have migrated off of legacy subscription + overrides) + """ - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + replace_adjustments: Optional[Iterable[ReplaceAdjustment]] + """Plan adjustments to be replaced with additional adjustments on the subscription. - For plan/plan phase discounts, this can be a subset of prices. + (Only available for accounts that have migrated off of legacy subscription + overrides) """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + replace_prices: Optional[Iterable[ReplacePrice]] + """Plan prices to be replaced with additional prices on the subscription. - This is a number between 0 and 1. + (Only available for accounts that have migrated off of legacy subscription + overrides) """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + start_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + trial_duration_days: Optional[int] + """The duration of the trial period in days. - Number of usage units that this discount is for + If not provided, this defaults to the value specified in the plan. If `0` is + provided, the trial on the plan will be skipped. """ + usage_customer_ids: Optional[SequenceNotStr[str]] + """ + A list of customer IDs whose usage events will be aggregated and billed under + this subscription. By default, a subscription only considers usage events + associated with its attached customer's customer_id. When usage_customer_ids is + provided, the subscription includes usage events from the specified customers + only. Provided usage_customer_ids must be either the customer for this + subscription itself, or any of that customer's children. + """ -class PriceOverrideOverrideUnitPrice(TypedDict, total=False): - id: Required[str] - model_type: Required[Literal["unit"]] +class AddAdjustmentAdjustmentNewTieredPercentageDiscountTier(TypedDict, total=False): + lower_bound: Required[float] + """Exclusive lower bound of cumulative spend for this tier.""" - unit_config: Required[PriceOverrideOverrideUnitPriceUnitConfig] + percentage: Required[float] + """The percentage (0-1) discounted from spend in this tier.""" - discount: Optional[PriceOverrideOverrideUnitPriceDiscount] - """The subscription's override discount for the plan.""" + upper_bound: Optional[float] + """Inclusive upper bound of cumulative spend; null for the final open-ended tier.""" - 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.""" +class AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" -class PriceOverrideOverridePackagePricePackageConfig(TypedDict, total=False): - package_amount: Required[str] - """A currency amount to rate usage by""" - package_size: Optional[int] - """An integer amount to represent package size. +class AddAdjustmentAdjustmentNewTieredPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["tiered_percentage_discount"]] - For example, 1000 here would divide usage by 1000 before multiplying by - package_amount in rating - """ + tiers: Required[Iterable[AddAdjustmentAdjustmentNewTieredPercentageDiscountTier]] + + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" -class PriceOverrideOverridePackagePriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + filters: Optional[Iterable[AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter]] + """A list of filters that determine which prices this adjustment will apply to.""" - For plan/plan phase discounts, this can be a subset of prices. + 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. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" + + +AddAdjustmentAdjustment: TypeAlias = Union[ + NewPercentageDiscount, + NewUsageDiscount, + NewAmountDiscount, + NewMinimum, + NewMaximum, + AddAdjustmentAdjustmentNewTieredPercentageDiscount, +] + + +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 a number between 0 and 1. + This is the date that the adjustment will stop affecting prices on the + subscription. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + plan_phase_order: Optional[int] + """The phase to add this adjustment to.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + start_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The start date of the adjustment interval. - Number of usage units that this discount is for + 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 PriceOverrideOverridePackagePrice(TypedDict, total=False): - id: Required[str] +class AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigFilter(TypedDict, total=False): + """Configuration for a single property filter""" - model_type: Required[Literal["package"]] + property_key: Required[str] + """Event property key to filter on""" - package_config: Required[PriceOverrideOverridePackagePricePackageConfig] + property_value: Required[str] + """Event property value to match""" - discount: Optional[PriceOverrideOverridePackagePriceDiscount] - """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 AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier""" - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + unit_amount: Required[str] + """Amount per unit""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + tier_lower_bound: Optional[str] + """The lower bound for this tier""" -class PriceOverrideOverrideMatrixPriceMatrixConfigMatrixValue(TypedDict, total=False): - dimension_values: Required[List[Optional[str]]] - """One or two matrix keys to filter usage to this Matrix value by. +class AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfig(TypedDict, total=False): + """Configuration for bulk_with_filters pricing""" - For example, ["region", "tier"] could be used to filter cloud usage by a cloud - region and an instance tier. - """ + filters: Required[Iterable[AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigFilter]] + """Property filters to apply (all must match)""" - unit_amount: Required[str] - """Unit price for the specified dimension_values""" + tiers: Required[Iterable[AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigTier]] + """Bulk tiers for rating based on total usage volume""" -class PriceOverrideOverrideMatrixPriceMatrixConfig(TypedDict, total=False): - default_unit_amount: Required[str] - """Default per unit rate for any usage not bucketed into a specified matrix_value""" +AddPricePriceNewSubscriptionBulkWithFiltersPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] - dimensions: Required[List[Optional[str]]] - """One or two event property values to evaluate matrix groups by""" - matrix_values: Required[Iterable[PriceOverrideOverrideMatrixPriceMatrixConfigMatrixValue]] - """Matrix values for specified matrix grouping keys""" +class AddPricePriceNewSubscriptionBulkWithFiltersPrice(TypedDict, total=False): + bulk_with_filters_config: Required[AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfig] + """Configuration for bulk_with_filters pricing""" + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" -class PriceOverrideOverrideMatrixPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + item_id: Required[str] + """The id of the item the price will be associated with.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + model_type: Required[Literal["bulk_with_filters"]] + """The pricing model type""" - 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. + 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[NewBillingCycleConfiguration] + """ + 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`. + conversion_rate_config: Optional[AddPricePriceNewSubscriptionBulkWithFiltersPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" - Number of usage units that this discount is for + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" -class PriceOverrideOverrideMatrixPrice(TypedDict, total=False): - id: Required[str] - - matrix_config: Required[PriceOverrideOverrideMatrixPriceMatrixConfig] + external_price_id: Optional[str] + """An alias for the price.""" - model_type: Required[Literal["matrix"]] + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - discount: Optional[PriceOverrideOverrideMatrixPriceDiscount] - """The subscription's override discount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + If unspecified, a single invoice is produced per billing cycle. + """ - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. -class PriceOverrideOverrideTieredPriceTieredConfigTier(TypedDict, total=False): - first_unit: Required[float] - """Inclusive tier starting value""" + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - unit_amount: Required[str] - """Amount per unit""" + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ - last_unit: Optional[float] - """Exclusive tier ending value. If null, this is treated as the last tier""" +class AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue( + TypedDict, total=False +): + first_dimension_value: Required[str] -class PriceOverrideOverrideTieredPriceTieredConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideTieredPriceTieredConfigTier]] - """Tiers for rating based on total usage quantities into the specified tier""" + unit_amount: Required[str] + second_dimension_value: Optional[str] -class PriceOverrideOverrideTieredPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" +class AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup( + TypedDict, total=False +): + above_threshold_discount_percentage: Required[str] + """Discount rate applied to spend above the threshold.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + below_threshold_discount_percentage: Required[str] + """Discount rate applied to spend at or below the threshold. - For plan/plan phase discounts, this can be a subset of prices. + Set to 0 for no baseline discount. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + cell_coordinates: Required[str] + """Semicolon-separated list of matrix cell coordinates targeted by this group. - This is a number between 0 and 1. + Each coordinate is `first,second` when the matrix has two dimensions, or just + `first` for a single-dimension matrix. Example: `blue,circle;green,triangle`. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + threshold_amount: Required[str] - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + description: Optional[str] - Number of usage units that this discount is for - """ +class AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig( + TypedDict, total=False +): + """Configuration for matrix_with_threshold_discounts pricing""" -class PriceOverrideOverrideTieredPrice(TypedDict, total=False): - id: Required[str] + default_unit_amount: Required[str] + """Unit price used for usage that does not match any defined matrix cell.""" - model_type: Required[Literal["tiered"]] + first_dimension: Required[str] + """First matrix dimension key.""" - tiered_config: Required[PriceOverrideOverrideTieredPriceTieredConfig] + matrix_values: Required[ + Iterable[ + AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue + ] + ] + """Per-cell unit prices.""" - discount: Optional[PriceOverrideOverrideTieredPriceDiscount] - """The subscription's override discount for the plan.""" + second_dimension: Optional[str] + """Optional second matrix dimension key.""" - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + threshold_discount_groups: Iterable[ + AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup + ] - 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.""" +AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] -class PriceOverrideOverrideTieredBpsPriceTieredBpsConfigTier(TypedDict, total=False): - bps: Required[float] - """Per-event basis point rate""" +class AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - minimum_amount: Required[str] - """Inclusive tier starting value""" + item_id: Required[str] + """The id of the item the price will be associated with.""" - maximum_amount: Optional[str] - """Exclusive tier ending value""" + matrix_with_threshold_discounts_config: Required[ + AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + ] + """Configuration for matrix_with_threshold_discounts pricing""" - per_unit_maximum: Optional[str] - """Per unit maximum to charge""" + model_type: Required[Literal["matrix_with_threshold_discounts"]] + """The pricing model type""" + name: Required[str] + """The name of the price.""" -class PriceOverrideOverrideTieredBpsPriceTieredBpsConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideTieredBpsPriceTieredBpsConfigTier]] + 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. """ - Tiers for a Graduated BPS pricing model, where usage is bucketed into specified - tiers + + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" -class PriceOverrideOverrideTieredBpsPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + conversion_rate_config: Optional[AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceConversionRateConfig] + """The configuration for the 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. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + external_price_id: Optional[str] + """An alias for the price.""" - For plan/plan phase discounts, this can be a subset of prices. + 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""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. - This is a number between 0 and 1. + If unspecified, a single invoice is produced per billing cycle. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - Number of usage units that this discount is for + 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 PriceOverrideOverrideTieredBpsPrice(TypedDict, total=False): - id: Required[str] - model_type: Required[Literal["tiered_bps"]] +class AddPricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single tiered with proration tier""" - tiered_bps_config: Required[PriceOverrideOverrideTieredBpsPriceTieredBpsConfig] + tier_lower_bound: Required[str] + """Inclusive tier starting value""" - discount: Optional[PriceOverrideOverrideTieredBpsPriceDiscount] - """The subscription's override discount for the plan.""" + unit_amount: Required[str] + """Amount per unit""" - 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.""" +class AddPricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfig(TypedDict, total=False): + """Configuration for tiered_with_proration pricing""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + tiers: Required[Iterable[AddPricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfigTier]] + """ + Tiers for rating based on total usage quantities into the specified tier with + proration + """ -class PriceOverrideOverrideBpsPriceBpsConfig(TypedDict, total=False): - bps: Required[float] - """Basis point take rate per event""" +AddPricePriceNewSubscriptionTieredWithProrationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] - per_unit_maximum: Optional[str] - """Optional currency amount maximum to cap spend per event""" +class AddPricePriceNewSubscriptionTieredWithProrationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" -class PriceOverrideOverrideBpsPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + item_id: Required[str] + """The id of the item the price will be associated with.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + model_type: Required[Literal["tiered_with_proration"]] + """The pricing model type""" - 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[ + AddPricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfig + ] + """Configuration for tiered_with_proration pricing""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - This is a number between 0 and 1. + Only needed if the price is usage-based. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" - - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + 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. + """ - Number of usage units that this discount is for + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" -class PriceOverrideOverrideBpsPrice(TypedDict, total=False): - id: Required[str] + conversion_rate_config: Optional[AddPricePriceNewSubscriptionTieredWithProrationPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" - bps_config: Required[PriceOverrideOverrideBpsPriceBpsConfig] + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ - model_type: Required[Literal["bps"]] + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" - 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.""" - - 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceOverrideOverrideBulkBpsPriceBulkBpsConfigTier(TypedDict, total=False): - bps: Required[float] - """Basis points to rate on""" + If unspecified, a single invoice is produced per billing cycle. + """ - maximum_amount: Optional[str] - """Upper bound for tier""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - per_unit_maximum: Optional[str] - """The maximum amount to charge for any one event""" + 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 PriceOverrideOverrideBulkBpsPriceBulkBpsConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideBulkBpsPriceBulkBpsConfigTier]] + reference_id: Optional[str] """ - Tiers for a bulk BPS pricing model where all usage is aggregated to a single - tier based on total volume + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ -class PriceOverrideOverrideBulkBpsPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] +class AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig( + TypedDict, total=False +): + """Configuration for grouped_with_min_max_thresholds pricing""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + grouping_key: Required[str] + """The event property used to group before applying thresholds""" - 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. - """ + maximum_charge: Required[str] + """The maximum amount to charge each group""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + minimum_charge: Required[str] + """The minimum amount to charge each group, regardless of usage""" - This is a number between 0 and 1. - """ + per_unit_rate: Required[str] + """The base price charged per group""" - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. +AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] - Number of usage units that this discount is for - """ +class AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" -class PriceOverrideOverrideBulkBpsPrice(TypedDict, total=False): - id: Required[str] + grouped_with_min_max_thresholds_config: Required[ + AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + ] + """Configuration for grouped_with_min_max_thresholds pricing""" - bulk_bps_config: Required[PriceOverrideOverrideBulkBpsPriceBulkBpsConfig] + item_id: Required[str] + """The id of the item the price will be associated with.""" - model_type: Required[Literal["bulk_bps"]] + model_type: Required[Literal["grouped_with_min_max_thresholds"]] + """The pricing model type""" - discount: Optional[PriceOverrideOverrideBulkBpsPriceDiscount] - """The subscription's override discount for the plan.""" + name: Required[str] + """The name of the price.""" - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + Only needed if the price is usage-based. + """ - minimum_amount: Optional[str] - """The subscription's override minimum amount 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[NewBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ -class PriceOverrideOverrideBulkPriceBulkConfigTier(TypedDict, total=False): - unit_amount: Required[str] - """Amount per unit""" + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" - maximum_units: Optional[float] - """Upper bound for this tier""" + conversion_rate_config: Optional[AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceConversionRateConfig] + """The configuration for the 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. + """ -class PriceOverrideOverrideBulkPriceBulkConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideBulkPriceBulkConfigTier]] - """Bulk tiers for rating based on total usage volume""" + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] + """An alias for the price.""" -class PriceOverrideOverrideBulkPriceDiscount(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[NewBillingCycleConfiguration] + """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`. + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`""" + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ - usage_discount: Optional[float] - """Only available if discount_type is `usage`. - Number of usage units that this discount is for - """ +class AddPricePriceNewSubscriptionCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig( + TypedDict, total=False +): + """Configuration for cumulative_grouped_allocation pricing""" + cumulative_allocation: Required[str] + """The overall allocation across all groups""" -class PriceOverrideOverrideBulkPrice(TypedDict, total=False): - id: Required[str] + group_allocation: Required[str] + """The allocation per individual group""" - bulk_config: Required[PriceOverrideOverrideBulkPriceBulkConfig] + grouping_key: Required[str] + """The event property used to group usage before applying allocations""" - model_type: Required[Literal["bulk"]] + unit_amount: Required[str] + """The amount to charge for each unit outside of the allocation""" - discount: Optional[PriceOverrideOverrideBulkPriceDiscount] - """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.""" +AddPricePriceNewSubscriptionCumulativeGroupedAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] - 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.""" +class AddPricePriceNewSubscriptionCumulativeGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + cumulative_grouped_allocation_config: Required[ + AddPricePriceNewSubscriptionCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + ] + """Configuration for cumulative_grouped_allocation pricing""" -class PriceOverrideOverrideThresholdTotalAmountPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + item_id: Required[str] + """The id of the item the price will be associated with.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + model_type: Required[Literal["cumulative_grouped_allocation"]] + """The pricing model type""" - 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. + 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[NewBillingCycleConfiguration] + """ + 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`. + conversion_rate_config: Optional[AddPricePriceNewSubscriptionCumulativeGroupedAllocationPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" - Number of usage units that this discount is for + currency: Optional[str] """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] + """An alias for the price.""" -class PriceOverrideOverrideThresholdTotalAmountPrice(TypedDict, total=False): - id: Required[str] + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - model_type: Required[Literal["threshold_total_amount"]] + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - threshold_total_amount_config: Required[Dict[str, object]] + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. - discount: Optional[PriceOverrideOverrideThresholdTotalAmountPriceDiscount] - """The subscription's override discount for the plan.""" + If unspecified, a single invoice is produced per billing cycle. + """ - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + 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 PriceOverrideOverrideTieredPackagePriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" +class AddPricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue( + TypedDict, total=False +): + """Per-dimension credit price for the daily credit allowance model.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + dimension_values: Required[SequenceNotStr[Optional[str]]] + """One or two matrix keys to filter usage to this value by. - For plan/plan phase discounts, this can be a subset of prices. + For example, ["model"] could be used to apply a different credit rate to each AI + model. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + unit_amount: Required[str] + """Credits charged per unit of usage matching the specified dimension_values""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfig(TypedDict, total=False): + """Configuration for daily_credit_allowance pricing""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + daily_allowance: Required[str] + """Credits granted per day. Lose-it-or-use-it; does not roll over.""" - Number of usage units that this discount is for + default_unit_amount: Required[str] + """ + Default per-unit credit rate for any usage not bucketed into a specified + matrix_value """ + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" -class PriceOverrideOverrideTieredPackagePrice(TypedDict, total=False): - id: Required[str] + event_day_property: Required[str] + """Event property whose value identifies the day bucket the event belongs to (e.g. - model_type: Required[Literal["tiered_package"]] + 'event_day' set to an ISO date string in the customer's timezone). The allowance + resets per distinct value of this property. + """ - tiered_package_config: Required[Dict[str, object]] + matrix_values: Required[ + Iterable[AddPricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue] + ] + """Per-dimension credit rates""" - discount: Optional[PriceOverrideOverrideTieredPackagePriceDiscount] - """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.""" +AddPricePriceNewSubscriptionDailyCreditAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] - 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.""" +class AddPricePriceNewSubscriptionDailyCreditAllowancePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + daily_credit_allowance_config: Required[ + AddPricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfig + ] + """Configuration for daily_credit_allowance pricing""" -class PriceOverrideOverrideTieredWithMinimumPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + item_id: Required[str] + """The id of the item the price will be associated with.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + model_type: Required[Literal["daily_credit_allowance"]] + """The pricing model type""" - 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. + 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[NewBillingCycleConfiguration] + """ + 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`. + conversion_rate_config: Optional[AddPricePriceNewSubscriptionDailyCreditAllowancePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" - Number of usage units that this discount is for + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" -class PriceOverrideOverrideTieredWithMinimumPrice(TypedDict, total=False): - id: Required[str] + external_price_id: Optional[str] + """An alias for the price.""" - model_type: Required[Literal["tiered_with_minimum"]] + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - tiered_with_minimum_config: Required[Dict[str, object]] + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - discount: Optional[PriceOverrideOverrideTieredWithMinimumPriceDiscount] - """The subscription's override discount for the plan.""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + If unspecified, a single invoice is produced per billing cycle. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + 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 PriceOverrideOverridePackageWithAllocationPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ - 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 AddPricePriceNewSubscriptionMeteredAllowancePriceMeteredAllowanceConfig(TypedDict, total=False): + """Configuration for metered_allowance pricing""" - For plan/plan phase discounts, this can be a subset of prices. + allowance_grouping_value: Required[str] + """ + The grouping_key value whose summed quantity represents the allowance for this + period (e.g. 'storage_snapshot' emitting 3 × avg storage). Capped at consumption + — credit can never exceed actual usage. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + consumption_grouping_value: Required[str] + """The grouping_key value whose summed quantity represents consumption (e.g. - This is a number between 0 and 1. + 'download'). Charged at unit_amount. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + grouping_key: Required[str] + """ + Event property used to partition the metric into consumption and allowance + quantities (e.g. 'event_name'). The metric is queried with this key and the two + values below select which partition is which. + """ - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + unit_amount: Required[str] + """Per-unit price applied to gross consumption and to the allowance credit.""" - Number of usage units that this discount is for - """ + allowance_display_name: str + """Sub-line label for the credit row (e.g. 'Up to 3x free egress').""" + consumption_display_name: str + """Sub-line label for the gross consumption row (e.g. 'bytes gotten').""" -class PriceOverrideOverridePackageWithAllocationPrice(TypedDict, total=False): - id: Required[str] - model_type: Required[Literal["package_with_allocation"]] +AddPricePriceNewSubscriptionMeteredAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] - package_with_allocation_config: Required[Dict[str, object]] - discount: Optional[PriceOverrideOverridePackageWithAllocationPriceDiscount] - """The subscription's override discount for the plan.""" +class AddPricePriceNewSubscriptionMeteredAllowancePrice(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 price will be associated with.""" - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + metered_allowance_config: Required[AddPricePriceNewSubscriptionMeteredAllowancePriceMeteredAllowanceConfig] + """Configuration for metered_allowance pricing""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + model_type: Required[Literal["metered_allowance"]] + """The pricing model type""" + + 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. + """ -class PriceOverrideOverrideUnitWithPercentPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + conversion_rate_config: Optional[AddPricePriceNewSubscriptionMeteredAllowancePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" - For plan/plan phase discounts, this can be a subset of prices. + currency: Optional[str] """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + external_price_id: Optional[str] + """An alias for the price.""" - This is a number between 0 and 1. + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. - Number of usage units that this discount is for + If unspecified, a single invoice is produced per billing cycle. """ + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. -class PriceOverrideOverrideUnitWithPercentPrice(TypedDict, total=False): - id: Required[str] + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - model_type: Required[Literal["unit_with_percent"]] + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ - unit_with_percent_config: Required[Dict[str, object]] - discount: Optional[PriceOverrideOverrideUnitWithPercentPriceDiscount] - """The subscription's override discount for the plan.""" +class AddPricePriceNewSubscriptionPercentCompositePricePercentConfig(TypedDict, total=False): + """Configuration for percent pricing""" - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + percent: Required[float] + """Fraction of the component subtotals to charge (0 < percent <= 1).""" maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + """Maximum amount to charge. If unset, the fee has no upper bound.""" minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" - - -PriceOverride = Union[ - PriceOverrideOverrideUnitPrice, - PriceOverrideOverridePackagePrice, - PriceOverrideOverrideMatrixPrice, - PriceOverrideOverrideTieredPrice, - PriceOverrideOverrideTieredBpsPrice, - PriceOverrideOverrideBpsPrice, - PriceOverrideOverrideBulkBpsPrice, - PriceOverrideOverrideBulkPrice, - PriceOverrideOverrideThresholdTotalAmountPrice, - PriceOverrideOverrideTieredPackagePrice, - PriceOverrideOverrideTieredWithMinimumPrice, - PriceOverrideOverridePackageWithAllocationPrice, - PriceOverrideOverrideUnitWithPercentPrice, -] + """Minimum amount to charge. If unset, the fee is bounded below by 0.""" + + prorated: bool + """If true, the minimum_amount is prorated based on the service period. + + The maximum_amount is an absolute cap (never prorated), and the percent applied + to upstream subtotals is never prorated either. + """ + + +AddPricePriceNewSubscriptionPercentCompositePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewSubscriptionPercentCompositePrice(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 price will be associated with.""" + + model_type: Required[Literal["percent"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + percent_config: Required[AddPricePriceNewSubscriptionPercentCompositePricePercentConfig] + """Configuration for percent pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewSubscriptionPercentCompositePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 AddPricePriceNewSubscriptionEventOutputPriceEventOutputConfig(TypedDict, total=False): + """Configuration for event_output pricing""" + + unit_rating_key: Required[str] + """The key in the event data to extract the unit rate from.""" + + default_unit_rate: Optional[str] + """ + If provided, this amount will be used as the unit rate when an event does not + have a value for the `unit_rating_key`. If not provided, events missing a unit + rate will be ignored. + """ + + grouping_key: Optional[str] + """An optional key in the event data to group by (e.g., event ID). + + All events will also be grouped by their unit rate. + """ + + +AddPricePriceNewSubscriptionEventOutputPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewSubscriptionEventOutputPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + event_output_config: Required[AddPricePriceNewSubscriptionEventOutputPriceEventOutputConfig] + """Configuration for event_output pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["event_output"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewSubscriptionEventOutputPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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[ + NewSubscriptionUnitPriceParam, + NewSubscriptionTieredPriceParam, + NewSubscriptionBulkPriceParam, + AddPricePriceNewSubscriptionBulkWithFiltersPrice, + NewSubscriptionPackagePriceParam, + NewSubscriptionMatrixPriceParam, + NewSubscriptionThresholdTotalAmountPriceParam, + NewSubscriptionTieredPackagePriceParam, + NewSubscriptionTieredWithMinimumPriceParam, + NewSubscriptionGroupedTieredPriceParam, + NewSubscriptionTieredPackageWithMinimumPriceParam, + NewSubscriptionPackageWithAllocationPriceParam, + NewSubscriptionUnitWithPercentPriceParam, + NewSubscriptionMatrixWithAllocationPriceParam, + AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPrice, + AddPricePriceNewSubscriptionTieredWithProrationPrice, + NewSubscriptionUnitWithProrationPriceParam, + NewSubscriptionGroupedAllocationPriceParam, + NewSubscriptionBulkWithProrationPriceParam, + NewSubscriptionGroupedWithProratedMinimumPriceParam, + NewSubscriptionGroupedWithMeteredMinimumPriceParam, + AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPrice, + NewSubscriptionMatrixWithDisplayNamePriceParam, + NewSubscriptionGroupedTieredPackagePriceParam, + NewSubscriptionMaxGroupTieredPackagePriceParam, + NewSubscriptionScalableMatrixWithUnitPricingPriceParam, + NewSubscriptionScalableMatrixWithTieredPricingPriceParam, + NewSubscriptionCumulativeGroupedBulkPriceParam, + AddPricePriceNewSubscriptionCumulativeGroupedAllocationPrice, + AddPricePriceNewSubscriptionDailyCreditAllowancePrice, + AddPricePriceNewSubscriptionMeteredAllowancePrice, + NewSubscriptionMinimumCompositePriceParam, + AddPricePriceNewSubscriptionPercentCompositePrice, + AddPricePriceNewSubscriptionEventOutputPrice, +] + + +class AddPrice(TypedDict, total=False): + allocation_price: Optional[NewAllocationPrice] + """The definition of a new allocation price to create and add to the subscription.""" + + discounts: Optional[Iterable[DiscountOverrideParam]] + """[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. + """ + + metric_parameter_overrides: Optional[Dict[str, object]] + """Override values for parameterized billable metric variables. + + Keys are parameter names, values are the override values. + """ + + 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] + """New subscription price request body params.""" + + 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 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 ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountTier(TypedDict, total=False): + lower_bound: Required[float] + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: Required[float] + """The percentage (0-1) discounted from spend in this tier.""" + + upper_bound: Optional[float] + """Inclusive upper bound of cumulative spend; null for the final open-ended tier.""" + + +class ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountFilter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class ReplaceAdjustmentAdjustmentNewTieredPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["tiered_percentage_discount"]] + + tiers: Required[Iterable[ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountTier]] + + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[Iterable[ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountFilter]] + """A list of filters that determine which prices this adjustment will apply to.""" + + 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. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" + + +ReplaceAdjustmentAdjustment: TypeAlias = Union[ + NewPercentageDiscount, + NewUsageDiscount, + NewAmountDiscount, + NewMinimum, + NewMaximum, + ReplaceAdjustmentAdjustmentNewTieredPercentageDiscount, +] + + +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 ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigFilter(TypedDict, total=False): + """Configuration for a single property filter""" + + property_key: Required[str] + """Event property key to filter on""" + + property_value: Required[str] + """Event property value to match""" + + +class ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier""" + + unit_amount: Required[str] + """Amount per unit""" + + tier_lower_bound: Optional[str] + """The lower bound for this tier""" + + +class ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfig(TypedDict, total=False): + """Configuration for bulk_with_filters pricing""" + + filters: Required[Iterable[ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigFilter]] + """Property filters to apply (all must match)""" + + tiers: Required[Iterable[ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +ReplacePricePriceNewSubscriptionBulkWithFiltersPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionBulkWithFiltersPrice(TypedDict, total=False): + bulk_with_filters_config: Required[ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfig] + """Configuration for bulk_with_filters pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk_with_filters"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewSubscriptionBulkWithFiltersPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue( + TypedDict, total=False +): + first_dimension_value: Required[str] + + unit_amount: Required[str] + + second_dimension_value: Optional[str] + + +class ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup( + TypedDict, total=False +): + above_threshold_discount_percentage: Required[str] + """Discount rate applied to spend above the threshold.""" + + below_threshold_discount_percentage: Required[str] + """Discount rate applied to spend at or below the threshold. + + Set to 0 for no baseline discount. + """ + + cell_coordinates: Required[str] + """Semicolon-separated list of matrix cell coordinates targeted by this group. + + Each coordinate is `first,second` when the matrix has two dimensions, or just + `first` for a single-dimension matrix. Example: `blue,circle;green,triangle`. + """ + + threshold_amount: Required[str] + + description: Optional[str] + + +class ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig( + TypedDict, total=False +): + """Configuration for matrix_with_threshold_discounts pricing""" + + default_unit_amount: Required[str] + """Unit price used for usage that does not match any defined matrix cell.""" + + first_dimension: Required[str] + """First matrix dimension key.""" + + matrix_values: Required[ + Iterable[ + ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue + ] + ] + """Per-cell unit prices.""" + + second_dimension: Optional[str] + """Optional second matrix dimension key.""" + + threshold_discount_groups: Iterable[ + ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup + ] + + +ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPrice(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 price will be associated with.""" + + matrix_with_threshold_discounts_config: Required[ + ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + ] + """Configuration for matrix_with_threshold_discounts pricing""" + + model_type: Required[Literal["matrix_with_threshold_discounts"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ + ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceConversionRateConfig + ] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single tiered with proration tier""" + + tier_lower_bound: Required[str] + """Inclusive tier starting value""" + + unit_amount: Required[str] + """Amount per unit""" + + +class ReplacePricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfig(TypedDict, total=False): + """Configuration for tiered_with_proration pricing""" + + tiers: Required[Iterable[ReplacePricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfigTier]] + """ + Tiers for rating based on total usage quantities into the specified tier with + proration + """ + + +ReplacePricePriceNewSubscriptionTieredWithProrationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionTieredWithProrationPrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered_with_proration"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_with_proration_config: Required[ + ReplacePricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfig + ] + """Configuration for tiered_with_proration pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewSubscriptionTieredWithProrationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig( + TypedDict, total=False +): + """Configuration for grouped_with_min_max_thresholds pricing""" + + grouping_key: Required[str] + """The event property used to group before applying thresholds""" + + maximum_charge: Required[str] + """The maximum amount to charge each group""" + + minimum_charge: Required[str] + """The minimum amount to charge each group, regardless of usage""" + + per_unit_rate: Required[str] + """The base price charged per group""" + + +ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_with_min_max_thresholds_config: Required[ + ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + ] + """Configuration for grouped_with_min_max_thresholds pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_min_max_thresholds"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ + ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceConversionRateConfig + ] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig( + TypedDict, total=False +): + """Configuration for cumulative_grouped_allocation pricing""" + + cumulative_allocation: Required[str] + """The overall allocation across all groups""" + + group_allocation: Required[str] + """The allocation per individual group""" + + grouping_key: Required[str] + """The event property used to group usage before applying allocations""" + + unit_amount: Required[str] + """The amount to charge for each unit outside of the allocation""" + + +ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_allocation_config: Required[ + ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + ] + """Configuration for cumulative_grouped_allocation pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ + ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPriceConversionRateConfig + ] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue( + TypedDict, total=False +): + """Per-dimension credit price for the daily credit allowance model.""" + + dimension_values: Required[SequenceNotStr[Optional[str]]] + """One or two matrix keys to filter usage to this value by. + + For example, ["model"] could be used to apply a different credit rate to each AI + model. + """ + + unit_amount: Required[str] + """Credits charged per unit of usage matching the specified dimension_values""" + + +class ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfig(TypedDict, total=False): + """Configuration for daily_credit_allowance pricing""" + + daily_allowance: Required[str] + """Credits granted per day. Lose-it-or-use-it; does not roll over.""" + + default_unit_amount: Required[str] + """ + Default per-unit credit rate for any usage not bucketed into a specified + matrix_value + """ + + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" + + event_day_property: Required[str] + """Event property whose value identifies the day bucket the event belongs to (e.g. + + 'event_day' set to an ISO date string in the customer's timezone). The allowance + resets per distinct value of this property. + """ + + matrix_values: Required[ + Iterable[ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue] + ] + """Per-dimension credit rates""" + + +ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionDailyCreditAllowancePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + daily_credit_allowance_config: Required[ + ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfig + ] + """Configuration for daily_credit_allowance pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["daily_credit_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionMeteredAllowancePriceMeteredAllowanceConfig(TypedDict, total=False): + """Configuration for metered_allowance pricing""" + + allowance_grouping_value: Required[str] + """ + The grouping_key value whose summed quantity represents the allowance for this + period (e.g. 'storage_snapshot' emitting 3 × avg storage). Capped at consumption + — credit can never exceed actual usage. + """ + + consumption_grouping_value: Required[str] + """The grouping_key value whose summed quantity represents consumption (e.g. + + 'download'). Charged at unit_amount. + """ + + grouping_key: Required[str] + """ + Event property used to partition the metric into consumption and allowance + quantities (e.g. 'event_name'). The metric is queried with this key and the two + values below select which partition is which. + """ + + unit_amount: Required[str] + """Per-unit price applied to gross consumption and to the allowance credit.""" + + allowance_display_name: str + """Sub-line label for the credit row (e.g. 'Up to 3x free egress').""" + + consumption_display_name: str + """Sub-line label for the gross consumption row (e.g. 'bytes gotten').""" + + +ReplacePricePriceNewSubscriptionMeteredAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionMeteredAllowancePrice(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 price will be associated with.""" + + metered_allowance_config: Required[ReplacePricePriceNewSubscriptionMeteredAllowancePriceMeteredAllowanceConfig] + """Configuration for metered_allowance pricing""" + + model_type: Required[Literal["metered_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewSubscriptionMeteredAllowancePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionPercentCompositePricePercentConfig(TypedDict, total=False): + """Configuration for percent pricing""" + + percent: Required[float] + """Fraction of the component subtotals to charge (0 < percent <= 1).""" + + maximum_amount: Optional[str] + """Maximum amount to charge. If unset, the fee has no upper bound.""" + + minimum_amount: Optional[str] + """Minimum amount to charge. If unset, the fee is bounded below by 0.""" + + prorated: bool + """If true, the minimum_amount is prorated based on the service period. + + The maximum_amount is an absolute cap (never prorated), and the percent applied + to upstream subtotals is never prorated either. + """ + + +ReplacePricePriceNewSubscriptionPercentCompositePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionPercentCompositePrice(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 price will be associated with.""" + + model_type: Required[Literal["percent"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + percent_config: Required[ReplacePricePriceNewSubscriptionPercentCompositePricePercentConfig] + """Configuration for percent pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewSubscriptionPercentCompositePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionEventOutputPriceEventOutputConfig(TypedDict, total=False): + """Configuration for event_output pricing""" + + unit_rating_key: Required[str] + """The key in the event data to extract the unit rate from.""" + + default_unit_rate: Optional[str] + """ + If provided, this amount will be used as the unit rate when an event does not + have a value for the `unit_rating_key`. If not provided, events missing a unit + rate will be ignored. + """ + + grouping_key: Optional[str] + """An optional key in the event data to group by (e.g., event ID). + + All events will also be grouped by their unit rate. + """ + + +ReplacePricePriceNewSubscriptionEventOutputPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionEventOutputPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + event_output_config: Required[ReplacePricePriceNewSubscriptionEventOutputPriceEventOutputConfig] + """Configuration for event_output pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["event_output"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewSubscriptionEventOutputPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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[ + NewSubscriptionUnitPriceParam, + NewSubscriptionTieredPriceParam, + NewSubscriptionBulkPriceParam, + ReplacePricePriceNewSubscriptionBulkWithFiltersPrice, + NewSubscriptionPackagePriceParam, + NewSubscriptionMatrixPriceParam, + NewSubscriptionThresholdTotalAmountPriceParam, + NewSubscriptionTieredPackagePriceParam, + NewSubscriptionTieredWithMinimumPriceParam, + NewSubscriptionGroupedTieredPriceParam, + NewSubscriptionTieredPackageWithMinimumPriceParam, + NewSubscriptionPackageWithAllocationPriceParam, + NewSubscriptionUnitWithPercentPriceParam, + NewSubscriptionMatrixWithAllocationPriceParam, + ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPrice, + ReplacePricePriceNewSubscriptionTieredWithProrationPrice, + NewSubscriptionUnitWithProrationPriceParam, + NewSubscriptionGroupedAllocationPriceParam, + NewSubscriptionBulkWithProrationPriceParam, + NewSubscriptionGroupedWithProratedMinimumPriceParam, + NewSubscriptionGroupedWithMeteredMinimumPriceParam, + ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPrice, + NewSubscriptionMatrixWithDisplayNamePriceParam, + NewSubscriptionGroupedTieredPackagePriceParam, + NewSubscriptionMaxGroupTieredPackagePriceParam, + NewSubscriptionScalableMatrixWithUnitPricingPriceParam, + NewSubscriptionScalableMatrixWithTieredPricingPriceParam, + NewSubscriptionCumulativeGroupedBulkPriceParam, + ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPrice, + ReplacePricePriceNewSubscriptionDailyCreditAllowancePrice, + ReplacePricePriceNewSubscriptionMeteredAllowancePrice, + NewSubscriptionMinimumCompositePriceParam, + ReplacePricePriceNewSubscriptionPercentCompositePrice, + ReplacePricePriceNewSubscriptionEventOutputPrice, +] + + +class ReplacePrice(TypedDict, total=False): + replaces_price_id: Required[str] + """The id of the price on the plan to replace in the subscription.""" + + allocation_price: Optional[NewAllocationPrice] + """The definition of a new allocation price to create and add to the subscription.""" + + discounts: Optional[Iterable[DiscountOverrideParam]] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's discounts for the replacement price. + """ + + external_price_id: Optional[str] + """The external price id of the price to add to the subscription.""" + + fixed_price_quantity: Optional[float] + """The new quantity of the price, if the price is a fixed price.""" + + maximum_amount: Optional[str] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's maximum amount for the replacement price. + """ + + metric_parameter_overrides: Optional[Dict[str, object]] + """Override values for parameterized billable metric variables. + + Keys are parameter names, values are the override values. + """ + + minimum_amount: Optional[str] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's minimum amount for the replacement price. + """ + + price: Optional[ReplacePricePrice] + """New subscription price request body params.""" + + price_id: Optional[str] + """The id of the price to add to the subscription.""" diff --git a/src/orb/types/subscription_fetch_costs_params.py b/src/orb/types/subscription_fetch_costs_params.py index b929aad3..38266115 100644 --- a/src/orb/types/subscription_fetch_costs_params.py +++ b/src/orb/types/subscription_fetch_costs_params.py @@ -12,6 +12,9 @@ class SubscriptionFetchCostsParams(TypedDict, total=False): + currency: Optional[str] + """The currency or custom pricing unit to use.""" + timeframe_end: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] """Costs returned are exclusive of `timeframe_end`.""" diff --git a/src/orb/types/subscription_fetch_costs_response.py b/src/orb/types/subscription_fetch_costs_response.py index af400e65..511a594c 100644 --- a/src/orb/types/subscription_fetch_costs_response.py +++ b/src/orb/types/subscription_fetch_costs_response.py @@ -1,273 +1,12 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional -from datetime import datetime +from typing import List -from .price import Price from .._models import BaseModel +from .shared.aggregated_cost import AggregatedCost -__all__ = ["SubscriptionFetchCostsResponse", "Data", "DataPerPriceCost"] - - -class DataPerPriceCost(BaseModel): - 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 - ... - } - ``` - """ - - subtotal: str - """Price's contributions for the timeframe, excluding any minimums and discounts.""" - - total: str - """Price's contributions for the timeframe, including minimums and discounts.""" - - quantity: Optional[float] = None - """The price's quantity for the timeframe""" - - -class Data(BaseModel): - per_price_costs: List[DataPerPriceCost] - - subtotal: str - """Total costs for the timeframe, excluding any minimums and discounts.""" - - timeframe_end: datetime - - timeframe_start: datetime - - total: str - """Total costs for the timeframe, including any minimums and discounts.""" +__all__ = ["SubscriptionFetchCostsResponse"] class SubscriptionFetchCostsResponse(BaseModel): - data: List[Data] + data: List[AggregatedCost] diff --git a/src/orb/types/subscription_fetch_schedule_response.py b/src/orb/types/subscription_fetch_schedule_response.py index 38a3999c..02227db6 100644 --- a/src/orb/types/subscription_fetch_schedule_response.py +++ b/src/orb/types/subscription_fetch_schedule_response.py @@ -26,6 +26,6 @@ class SubscriptionFetchScheduleResponse(BaseModel): end_date: Optional[datetime] = None - plan: Plan + plan: Optional[Plan] = None start_date: datetime diff --git a/src/orb/types/subscription_fetch_usage_params.py b/src/orb/types/subscription_fetch_usage_params.py index 08c7800f..6728382e 100644 --- a/src/orb/types/subscription_fetch_usage_params.py +++ b/src/orb/types/subscription_fetch_usage_params.py @@ -19,13 +19,6 @@ class SubscriptionFetchUsageParams(TypedDict, total=False): be specified together. """ - cursor: Optional[str] - """Cursor for pagination. - - This can be populated by the `next_cursor` value returned from the initial - request. - """ - first_dimension_key: Optional[str] first_dimension_value: Optional[str] @@ -36,12 +29,6 @@ class SubscriptionFetchUsageParams(TypedDict, total=False): group_by: Optional[str] """Groups per-price usage by the key provided.""" - limit: Optional[int] - """If including a `group_by`, the number of groups to fetch data for. - - Defaults to 1000. - """ - second_dimension_key: Optional[str] second_dimension_value: Optional[str] diff --git a/src/orb/types/subscription_list_params.py b/src/orb/types/subscription_list_params.py index 7fd530d2..08b86f7c 100644 --- a/src/orb/types/subscription_list_params.py +++ b/src/orb/types/subscription_list_params.py @@ -6,6 +6,7 @@ from datetime import datetime from typing_extensions import Literal, Annotated, TypedDict +from .._types import SequenceNotStr from .._utils import PropertyInfo __all__ = ["SubscriptionListParams"] @@ -27,11 +28,15 @@ class SubscriptionListParams(TypedDict, total=False): request. """ - customer_id: Optional[str] + customer_id: Optional[SequenceNotStr[str]] - external_customer_id: Optional[str] + external_customer_id: Optional[SequenceNotStr[str]] + + external_plan_id: Optional[str] limit: int """The number of items to fetch. Defaults to 20.""" + plan_id: Optional[str] + status: Optional[Literal["active", "ended", "upcoming"]] diff --git a/src/orb/types/subscription_price_intervals_params.py b/src/orb/types/subscription_price_intervals_params.py index a3791d1d..01e0e5a9 100644 --- a/src/orb/types/subscription_price_intervals_params.py +++ b/src/orb/types/subscription_price_intervals_params.py @@ -2,11 +2,53 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict +from .._types import SequenceNotStr from .._utils import PropertyInfo +from .shared_params.new_maximum import NewMaximum +from .shared_params.new_minimum import NewMinimum +from .shared_params.new_usage_discount import NewUsageDiscount +from .shared_params.new_amount_discount import NewAmountDiscount +from .shared.billing_cycle_relative_date import BillingCycleRelativeDate +from .shared_params.new_allocation_price import NewAllocationPrice +from .shared_params.new_floating_bulk_price import NewFloatingBulkPrice +from .shared_params.new_floating_unit_price import NewFloatingUnitPrice +from .shared_params.new_percentage_discount import NewPercentageDiscount +from .shared_params.new_floating_matrix_price import NewFloatingMatrixPrice +from .shared_params.new_floating_tiered_price import NewFloatingTieredPrice +from .shared_params.new_floating_package_price import NewFloatingPackagePrice +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .shared_params.new_floating_grouped_tiered_price import NewFloatingGroupedTieredPrice +from .shared_params.new_floating_tiered_package_price import NewFloatingTieredPackagePrice +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration +from .shared_params.new_floating_minimum_composite_price import NewFloatingMinimumCompositePrice +from .shared_params.new_floating_unit_with_percent_price import NewFloatingUnitWithPercentPrice +from .shared_params.new_floating_grouped_allocation_price import NewFloatingGroupedAllocationPrice +from .shared_params.new_floating_bulk_with_proration_price import NewFloatingBulkWithProrationPrice +from .shared_params.new_floating_tiered_with_minimum_price import NewFloatingTieredWithMinimumPrice +from .shared_params.new_floating_unit_with_proration_price import NewFloatingUnitWithProrationPrice +from .shared_params.new_floating_tiered_with_proration_price import NewFloatingTieredWithProrationPrice +from .shared_params.new_floating_grouped_tiered_package_price import NewFloatingGroupedTieredPackagePrice +from .shared_params.new_floating_matrix_with_allocation_price import NewFloatingMatrixWithAllocationPrice +from .shared_params.new_floating_threshold_total_amount_price import NewFloatingThresholdTotalAmountPrice +from .shared_params.new_floating_cumulative_grouped_bulk_price import NewFloatingCumulativeGroupedBulkPrice +from .shared_params.new_floating_package_with_allocation_price import NewFloatingPackageWithAllocationPrice +from .shared_params.new_floating_matrix_with_display_name_price import NewFloatingMatrixWithDisplayNamePrice +from .shared_params.new_floating_max_group_tiered_package_price import NewFloatingMaxGroupTieredPackagePrice +from .shared_params.new_floating_tiered_package_with_minimum_price import NewFloatingTieredPackageWithMinimumPrice +from .shared_params.new_floating_grouped_with_metered_minimum_price import NewFloatingGroupedWithMeteredMinimumPrice +from .shared_params.new_floating_grouped_with_prorated_minimum_price import NewFloatingGroupedWithProratedMinimumPrice +from .shared_params.new_floating_scalable_matrix_with_unit_pricing_price import ( + NewFloatingScalableMatrixWithUnitPricingPrice, +) +from .shared_params.new_floating_scalable_matrix_with_tiered_pricing_price import ( + NewFloatingScalableMatrixWithTieredPricingPrice, +) __all__ = [ "SubscriptionPriceIntervalsParams", @@ -17,38 +59,43 @@ "AddDiscountUsageDiscountCreationParams", "AddFixedFeeQuantityTransition", "AddPrice", - "AddPriceNewFloatingUnitPrice", - "AddPriceNewFloatingUnitPriceUnitConfig", - "AddPriceNewFloatingPackagePrice", - "AddPriceNewFloatingPackagePricePackageConfig", - "AddPriceNewFloatingMatrixPrice", - "AddPriceNewFloatingMatrixPriceMatrixConfig", - "AddPriceNewFloatingMatrixPriceMatrixConfigMatrixValue", - "AddPriceNewFloatingMatrixWithAllocationPrice", - "AddPriceNewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfig", - "AddPriceNewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfigMatrixValue", - "AddPriceNewFloatingTieredPrice", - "AddPriceNewFloatingTieredPriceTieredConfig", - "AddPriceNewFloatingTieredPriceTieredConfigTier", - "AddPriceNewFloatingTieredBpsPrice", - "AddPriceNewFloatingTieredBpsPriceTieredBpsConfig", - "AddPriceNewFloatingTieredBpsPriceTieredBpsConfigTier", - "AddPriceNewFloatingBpsPrice", - "AddPriceNewFloatingBpsPriceBpsConfig", - "AddPriceNewFloatingBulkBpsPrice", - "AddPriceNewFloatingBulkBpsPriceBulkBpsConfig", - "AddPriceNewFloatingBulkBpsPriceBulkBpsConfigTier", - "AddPriceNewFloatingBulkPrice", - "AddPriceNewFloatingBulkPriceBulkConfig", - "AddPriceNewFloatingBulkPriceBulkConfigTier", - "AddPriceNewFloatingThresholdTotalAmountPrice", - "AddPriceNewFloatingTieredPackagePrice", - "AddPriceNewFloatingTieredWithMinimumPrice", - "AddPriceNewFloatingPackageWithAllocationPrice", - "AddPriceNewFloatingTieredPackageWithMinimumPrice", - "AddPriceNewFloatingUnitWithPercentPrice", + "AddPriceNewFloatingBulkWithFiltersPrice", + "AddPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfig", + "AddPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigFilter", + "AddPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigTier", + "AddPriceNewFloatingBulkWithFiltersPriceConversionRateConfig", + "AddPriceNewFloatingMatrixWithThresholdDiscountsPrice", + "AddPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig", + "AddPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue", + "AddPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup", + "AddPriceNewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig", + "AddPriceNewFloatingGroupedWithMinMaxThresholdsPrice", + "AddPriceNewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig", + "AddPriceNewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig", + "AddPriceNewFloatingCumulativeGroupedAllocationPrice", + "AddPriceNewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig", + "AddPriceNewFloatingCumulativeGroupedAllocationPriceConversionRateConfig", + "AddPriceNewFloatingDailyCreditAllowancePrice", + "AddPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig", + "AddPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue", + "AddPriceNewFloatingDailyCreditAllowancePriceConversionRateConfig", + "AddPriceNewFloatingMeteredAllowancePrice", + "AddPriceNewFloatingMeteredAllowancePriceMeteredAllowanceConfig", + "AddPriceNewFloatingMeteredAllowancePriceConversionRateConfig", + "AddPriceNewFloatingPercentCompositePrice", + "AddPriceNewFloatingPercentCompositePricePercentConfig", + "AddPriceNewFloatingPercentCompositePriceConversionRateConfig", + "AddPriceNewFloatingEventOutputPrice", + "AddPriceNewFloatingEventOutputPriceEventOutputConfig", + "AddPriceNewFloatingEventOutputPriceConversionRateConfig", + "AddAdjustment", + "AddAdjustmentAdjustment", + "AddAdjustmentAdjustmentNewTieredPercentageDiscount", + "AddAdjustmentAdjustmentNewTieredPercentageDiscountTier", + "AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter", "Edit", "EditFixedFeeQuantityTransition", + "EditAdjustment", ] @@ -56,9 +103,28 @@ class SubscriptionPriceIntervalsParams(TypedDict, total=False): add: Iterable[Add] """A list of price intervals to add to the subscription.""" + add_adjustments: Iterable[AddAdjustment] + """A list of adjustments to add to the subscription.""" + + allow_invoice_credit_or_void: Optional[bool] + """ + If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + """ + + can_defer_billing: Optional[bool] + """ + If set, the default value to use for added/edited price intervals with an + end_date set. + """ + edit: Iterable[Edit] """A list of price intervals to edit on the subscription.""" + edit_adjustments: Iterable[EditAdjustment] + """A list of adjustments to edit on the subscription.""" + class AddDiscountAmountDiscountCreationParams(TypedDict, total=False): amount_discount: Required[float] @@ -87,7 +153,7 @@ class AddDiscountUsageDiscountCreationParams(TypedDict, total=False): """ -AddDiscount = Union[ +AddDiscount: TypeAlias = Union[ AddDiscountAmountDiscountCreationParams, AddDiscountPercentageDiscountCreationParams, AddDiscountUsageDiscountCreationParams, @@ -102,82 +168,60 @@ class AddFixedFeeQuantityTransition(TypedDict, total=False): """The quantity of the fixed fee quantity transition.""" -class AddPriceNewFloatingUnitPriceUnitConfig(TypedDict, total=False): - unit_amount: Required[str] - """Rate per unit of usage""" +class AddPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigFilter(TypedDict, total=False): + """Configuration for a single property filter""" + property_key: Required[str] + """Event property key to filter on""" -class AddPriceNewFloatingUnitPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] - """The cadence to bill for this price on.""" + property_value: Required[str] + """Event property value to match""" - 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.""" +class AddPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier""" - model_type: Required[Literal["unit"]] + unit_amount: Required[str] + """Amount per unit""" - name: Required[str] - """The name of the price.""" + tier_lower_bound: Optional[str] + """The lower bound for this tier""" - unit_config: Required[AddPriceNewFloatingUnitPriceUnitConfig] - billable_metric_id: Optional[str] - """The id of the billable metric for the price. +class AddPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfig(TypedDict, total=False): + """Configuration for bulk_with_filters pricing""" - 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. - """ - - 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""" + filters: Required[Iterable[AddPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigFilter]] + """Property filters to apply (all must match)""" + tiers: Required[Iterable[AddPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfigTier]] + """Bulk tiers for rating based on total usage volume""" -class AddPriceNewFloatingPackagePricePackageConfig(TypedDict, total=False): - package_amount: Required[str] - """A currency amount to rate usage by""" - package_size: Optional[int] - """An integer amount to represent package size. +AddPriceNewFloatingBulkWithFiltersPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] - For example, 1000 here would divide usage by 1000 before multiplying by - package_amount in rating - """ +class AddPriceNewFloatingBulkWithFiltersPrice(TypedDict, total=False): + bulk_with_filters_config: Required[AddPriceNewFloatingBulkWithFiltersPriceBulkWithFiltersConfig] + """Configuration for bulk_with_filters pricing""" -class AddPriceNewFloatingPackagePrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] + 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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["package"]] + model_type: Required[Literal["bulk_with_filters"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - package_config: Required[AddPriceNewFloatingPackagePricePackageConfig] - billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -190,6 +234,21 @@ class AddPriceNewFloatingPackagePrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPriceNewFloatingBulkWithFiltersPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -202,111 +261,101 @@ class AddPriceNewFloatingPackagePrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class AddPriceNewFloatingMatrixPriceMatrixConfigMatrixValue(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. + If unspecified, a single invoice is produced per billing cycle. """ - unit_amount: Required[str] - """Unit price for the specified dimension_values""" - + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" -class AddPriceNewFloatingMatrixPriceMatrixConfig(TypedDict, total=False): - default_unit_amount: Required[str] - """Default per unit rate for any usage not bucketed into a specified matrix_value""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - dimensions: Required[List[Optional[str]]] - """One or two event property values to evaluate matrix groups by""" + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - matrix_values: Required[Iterable[AddPriceNewFloatingMatrixPriceMatrixConfigMatrixValue]] - """Matrix values for specified matrix grouping keys""" +class AddPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue( + TypedDict, total=False +): + first_dimension_value: Required[str] -class AddPriceNewFloatingMatrixPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] - """The cadence to bill for this price on.""" + unit_amount: Required[str] - currency: Required[str] - """An ISO 4217 currency string for which this price is billed in.""" + second_dimension_value: Optional[str] - item_id: Required[str] - """The id of the item the plan will be associated with.""" - matrix_config: Required[AddPriceNewFloatingMatrixPriceMatrixConfig] +class AddPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup( + TypedDict, total=False +): + above_threshold_discount_percentage: Required[str] + """Discount rate applied to spend above the threshold.""" - model_type: Required[Literal["matrix"]] + below_threshold_discount_percentage: Required[str] + """Discount rate applied to spend at or below the threshold. - 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. + Set to 0 for no baseline discount. """ - 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. - """ + cell_coordinates: Required[str] + """Semicolon-separated list of matrix cell coordinates targeted by this group. - 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. + Each coordinate is `first,second` when the matrix has two dimensions, or just + `first` for a single-dimension matrix. Example: `blue,circle;green,triangle`. """ - invoice_grouping_key: Optional[str] - """The property used to group this price on an invoice""" + threshold_amount: Required[str] + description: Optional[str] -class AddPriceNewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfigMatrixValue(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. - """ +class AddPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig(TypedDict, total=False): + """Configuration for matrix_with_threshold_discounts pricing""" - unit_amount: Required[str] - """Unit price for the specified dimension_values""" + default_unit_amount: Required[str] + """Unit price used for usage that does not match any defined matrix cell.""" + first_dimension: Required[str] + """First matrix dimension key.""" -class AddPriceNewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfig(TypedDict, total=False): - allocation: Required[float] - """Allocation to be used to calculate the price""" + matrix_values: Required[ + Iterable[AddPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue] + ] + """Per-cell unit prices.""" - default_unit_amount: Required[str] - """Default per unit rate for any usage not bucketed into a specified matrix_value""" + second_dimension: Optional[str] + """Optional second matrix dimension key.""" + + threshold_discount_groups: Iterable[ + AddPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup + ] - dimensions: Required[List[Optional[str]]] - """One or two event property values to evaluate matrix groups by""" - matrix_values: Required[Iterable[AddPriceNewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfigMatrixValue]] - """Matrix values for specified matrix grouping keys""" +AddPriceNewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] -class AddPriceNewFloatingMatrixWithAllocationPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class AddPriceNewFloatingMatrixWithThresholdDiscountsPrice(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.""" + """The id of the item the price will be associated with.""" - matrix_with_allocation_config: Required[AddPriceNewFloatingMatrixWithAllocationPriceMatrixWithAllocationConfig] + matrix_with_threshold_discounts_config: Required[ + AddPriceNewFloatingMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + ] + """Configuration for matrix_with_threshold_discounts pricing""" - model_type: Required[Literal["matrix_with_allocation"]] + model_type: Required[Literal["matrix_with_threshold_discounts"]] + """The pricing model type""" name: Required[str] """The name of the price.""" @@ -323,6 +372,21 @@ class AddPriceNewFloatingMatrixWithAllocationPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPriceNewFloatingMatrixWithThresholdDiscountsPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -335,40 +399,65 @@ class AddPriceNewFloatingMatrixWithAllocationPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ -class AddPriceNewFloatingTieredPriceTieredConfigTier(TypedDict, total=False): - first_unit: Required[float] - """Inclusive tier starting value""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - unit_amount: Required[str] - """Amount per unit""" + 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 AddPriceNewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig(TypedDict, total=False): + """Configuration for grouped_with_min_max_thresholds pricing""" - last_unit: Optional[float] - """Exclusive tier ending value. If null, this is treated as the last tier""" + grouping_key: Required[str] + """The event property used to group before applying thresholds""" + maximum_charge: Required[str] + """The maximum amount to charge each group""" -class AddPriceNewFloatingTieredPriceTieredConfig(TypedDict, total=False): - tiers: Required[Iterable[AddPriceNewFloatingTieredPriceTieredConfigTier]] - """Tiers for rating based on total usage quantities into the specified tier""" + minimum_charge: Required[str] + """The minimum amount to charge each group, regardless of usage""" + per_unit_rate: Required[str] + """The base price charged per group""" -class AddPriceNewFloatingTieredPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] + +AddPriceNewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPriceNewFloatingGroupedWithMinMaxThresholdsPrice(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_min_max_thresholds_config: Required[ + AddPriceNewFloatingGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + ] + """Configuration for grouped_with_min_max_thresholds pricing""" + item_id: Required[str] - """The id of the item the plan will be associated with.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["tiered"]] + model_type: Required[Literal["grouped_with_min_max_thresholds"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - tiered_config: Required[AddPriceNewFloatingTieredPriceTieredConfig] - billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -381,6 +470,21 @@ class AddPriceNewFloatingTieredPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPriceNewFloatingGroupedWithMinMaxThresholdsPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -393,92 +497,61 @@ class AddPriceNewFloatingTieredPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class AddPriceNewFloatingTieredBpsPriceTieredBpsConfigTier(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 AddPriceNewFloatingTieredBpsPriceTieredBpsConfig(TypedDict, total=False): - tiers: Required[Iterable[AddPriceNewFloatingTieredBpsPriceTieredBpsConfigTier]] - """ - Tiers for a Graduated BPS pricing model, where usage is bucketed into specified - tiers + If unspecified, a single invoice is produced per billing cycle. """ + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" -class AddPriceNewFloatingTieredBpsPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] - """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.""" - - model_type: Required[Literal["tiered_bps"]] - - name: Required[str] - """The name of the price.""" - - tiered_bps_config: Required[AddPriceNewFloatingTieredBpsPriceTieredBpsConfig] - - billable_metric_id: Optional[str] - """The id of the billable metric for the price. + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - Only needed if the price is usage-based. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. """ - 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. - """ - external_price_id: Optional[str] - """An alias for the price.""" +class AddPriceNewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig(TypedDict, total=False): + """Configuration for cumulative_grouped_allocation pricing""" - fixed_price_quantity: Optional[float] - """ - If the Price represents a fixed cost, this represents the quantity of units - applied. - """ + cumulative_allocation: Required[str] + """The overall allocation across all groups""" - invoice_grouping_key: Optional[str] - """The property used to group this price on an invoice""" + group_allocation: Required[str] + """The allocation per individual group""" + grouping_key: Required[str] + """The event property used to group usage before applying allocations""" -class AddPriceNewFloatingBpsPriceBpsConfig(TypedDict, total=False): - bps: Required[float] - """Basis point take rate per event""" + unit_amount: Required[str] + """The amount to charge for each unit outside of the allocation""" - per_unit_maximum: Optional[str] - """Optional currency amount maximum to cap spend per event""" +AddPriceNewFloatingCumulativeGroupedAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] -class AddPriceNewFloatingBpsPrice(TypedDict, total=False): - bps_config: Required[AddPriceNewFloatingBpsPriceBpsConfig] - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class AddPriceNewFloatingCumulativeGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] """The cadence to bill for this price on.""" + cumulative_grouped_allocation_config: Required[ + AddPriceNewFloatingCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + ] + """Configuration for cumulative_grouped_allocation pricing""" + 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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["bps"]] + model_type: Required[Literal["cumulative_grouped_allocation"]] + """The pricing model type""" name: Required[str] """The name of the price.""" @@ -495,6 +568,21 @@ class AddPriceNewFloatingBpsPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPriceNewFloatingCumulativeGroupedAllocationPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -507,94 +595,83 @@ class AddPriceNewFloatingBpsPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class AddPriceNewFloatingBulkBpsPriceBulkBpsConfigTier(TypedDict, total=False): - bps: Required[float] - """Basis points to rate on""" - - maximum_amount: Optional[str] - """Upper bound for tier""" + If unspecified, a single invoice is produced per billing cycle. + """ - per_unit_maximum: Optional[str] - """The maximum amount to charge for any one event""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. -class AddPriceNewFloatingBulkBpsPriceBulkBpsConfig(TypedDict, total=False): - tiers: Required[Iterable[AddPriceNewFloatingBulkBpsPriceBulkBpsConfigTier]] - """ - Tiers for a bulk BPS pricing model where all usage is aggregated to a single - tier based on total volume + 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 AddPriceNewFloatingBulkBpsPrice(TypedDict, total=False): - bulk_bps_config: Required[AddPriceNewFloatingBulkBpsPriceBulkBpsConfig] - - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] - """The cadence to bill for this price on.""" +class AddPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue(TypedDict, total=False): + """Per-dimension credit price for the daily credit allowance model.""" - currency: Required[str] - """An ISO 4217 currency string for which this price is billed in.""" + dimension_values: Required[SequenceNotStr[Optional[str]]] + """One or two matrix keys to filter usage to this value by. - 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.""" + For example, ["model"] could be used to apply a different credit rate to each AI + model. + """ - billable_metric_id: Optional[str] - """The id of the billable metric for the price. + unit_amount: Required[str] + """Credits charged per unit of usage matching the specified dimension_values""" - 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 AddPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig(TypedDict, total=False): + """Configuration for daily_credit_allowance pricing""" - external_price_id: Optional[str] - """An alias for the price.""" + daily_allowance: Required[str] + """Credits granted per day. Lose-it-or-use-it; does not roll over.""" - fixed_price_quantity: Optional[float] + default_unit_amount: Required[str] """ - If the Price represents a fixed cost, this represents the quantity of units - applied. + Default per-unit credit rate for any usage not bucketed into a specified + matrix_value """ - invoice_grouping_key: Optional[str] - """The property used to group this price on an invoice""" - + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" -class AddPriceNewFloatingBulkPriceBulkConfigTier(TypedDict, total=False): - unit_amount: Required[str] - """Amount per unit""" + event_day_property: Required[str] + """Event property whose value identifies the day bucket the event belongs to (e.g. - maximum_units: Optional[float] - """Upper bound for this tier""" + 'event_day' set to an ISO date string in the customer's timezone). The allowance + resets per distinct value of this property. + """ + matrix_values: Required[Iterable[AddPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue]] + """Per-dimension credit rates""" -class AddPriceNewFloatingBulkPriceBulkConfig(TypedDict, total=False): - tiers: Required[Iterable[AddPriceNewFloatingBulkPriceBulkConfigTier]] - """Bulk tiers for rating based on total usage volume""" +AddPriceNewFloatingDailyCreditAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] -class AddPriceNewFloatingBulkPrice(TypedDict, total=False): - bulk_config: Required[AddPriceNewFloatingBulkPriceBulkConfig] - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class AddPriceNewFloatingDailyCreditAllowancePrice(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.""" + daily_credit_allowance_config: Required[AddPriceNewFloatingDailyCreditAllowancePriceDailyCreditAllowanceConfig] + """Configuration for daily_credit_allowance pricing""" + item_id: Required[str] - """The id of the item the plan will be associated with.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["bulk"]] + model_type: Required[Literal["daily_credit_allowance"]] + """The pricing model type""" name: Required[str] """The name of the price.""" @@ -611,6 +688,21 @@ class AddPriceNewFloatingBulkPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPriceNewFloatingDailyCreditAllowancePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -623,66 +715,80 @@ class AddPriceNewFloatingBulkPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class AddPriceNewFloatingThresholdTotalAmountPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] - """The cadence to bill for this price on.""" + If unspecified, a single invoice is produced per billing cycle. + """ - currency: Required[str] - """An ISO 4217 currency string for which this price is billed in.""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - item_id: Required[str] - """The id of the item the plan will be associated with.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - model_type: Required[Literal["threshold_total_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`. + """ - name: Required[str] - """The name of the price.""" - threshold_total_amount_config: Required[Dict[str, object]] +class AddPriceNewFloatingMeteredAllowancePriceMeteredAllowanceConfig(TypedDict, total=False): + """Configuration for metered_allowance pricing""" - billable_metric_id: Optional[str] - """The id of the billable metric for the price. + allowance_grouping_value: Required[str] + """ + The grouping_key value whose summed quantity represents the allowance for this + period (e.g. 'storage_snapshot' emitting 3 × avg storage). Capped at consumption + — credit can never exceed actual usage. + """ - Only needed if the price is usage-based. + consumption_grouping_value: Required[str] + """The grouping_key value whose summed quantity represents consumption (e.g. + + 'download'). Charged at unit_amount. """ - billed_in_advance: Optional[bool] + grouping_key: Required[str] """ - 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. + Event property used to partition the metric into consumption and allowance + quantities (e.g. 'event_name'). The metric is queried with this key and the two + values below select which partition is which. """ - external_price_id: Optional[str] - """An alias for the price.""" + unit_amount: Required[str] + """Per-unit price applied to gross consumption and to the allowance credit.""" - fixed_price_quantity: Optional[float] - """ - If the Price represents a fixed cost, this represents the quantity of units - applied. - """ + allowance_display_name: str + """Sub-line label for the credit row (e.g. 'Up to 3x free egress').""" - invoice_grouping_key: Optional[str] - """The property used to group this price on an invoice""" + consumption_display_name: str + """Sub-line label for the gross consumption row (e.g. 'bytes gotten').""" + + +AddPriceNewFloatingMeteredAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] -class AddPriceNewFloatingTieredPackagePrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class AddPriceNewFloatingMeteredAllowancePrice(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.""" + """The id of the item the price will be associated with.""" + + metered_allowance_config: Required[AddPriceNewFloatingMeteredAllowancePriceMeteredAllowanceConfig] + """Configuration for metered_allowance pricing""" - model_type: Required[Literal["tiered_package"]] + model_type: Required[Literal["metered_allowance"]] + """The pricing model type""" 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. @@ -695,6 +801,21 @@ class AddPriceNewFloatingTieredPackagePrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPriceNewFloatingMeteredAllowancePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -707,65 +828,66 @@ class AddPriceNewFloatingTieredPackagePrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class AddPriceNewFloatingTieredWithMinimumPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] - """The cadence to bill for this price on.""" + If unspecified, a single invoice is produced per billing cycle. + """ - currency: Required[str] - """An ISO 4217 currency string for which this price is billed in.""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - item_id: Required[str] - """The id of the item the plan will be associated with.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - model_type: Required[Literal["tiered_with_minimum"]] + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - name: Required[str] - """The name of the price.""" - tiered_with_minimum_config: Required[Dict[str, object]] +class AddPriceNewFloatingPercentCompositePricePercentConfig(TypedDict, total=False): + """Configuration for percent pricing""" - billable_metric_id: Optional[str] - """The id of the billable metric for the price. + percent: Required[float] + """Fraction of the component subtotals to charge (0 < percent <= 1).""" - Only needed if the price is usage-based. - """ + maximum_amount: Optional[str] + """Maximum amount to charge. If unset, the fee has no upper bound.""" - 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. - """ + minimum_amount: Optional[str] + """Minimum amount to charge. If unset, the fee is bounded below by 0.""" - external_price_id: Optional[str] - """An alias for the price.""" + prorated: bool + """If true, the minimum_amount is prorated based on the service period. - fixed_price_quantity: Optional[float] - """ - If the Price represents a fixed cost, this represents the quantity of units - applied. + The maximum_amount is an absolute cap (never prorated), and the percent applied + to upstream subtotals is never prorated either. """ - invoice_grouping_key: Optional[str] - """The property used to group this price on an invoice""" + +AddPriceNewFloatingPercentCompositePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] -class AddPriceNewFloatingPackageWithAllocationPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] +class AddPriceNewFloatingPercentCompositePrice(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.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["package_with_allocation"]] + model_type: Required[Literal["percent"]] + """The pricing model type""" name: Required[str] """The name of the price.""" - package_with_allocation_config: Required[Dict[str, object]] + percent_config: Required[AddPriceNewFloatingPercentCompositePricePercentConfig] + """Configuration for percent pricing""" billable_metric_id: Optional[str] """The id of the billable metric for the price. @@ -779,6 +901,21 @@ class AddPriceNewFloatingPackageWithAllocationPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPriceNewFloatingPercentCompositePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -791,66 +928,67 @@ class AddPriceNewFloatingPackageWithAllocationPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class AddPriceNewFloatingTieredPackageWithMinimumPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] - """The cadence to bill for this price on.""" + If unspecified, a single invoice is produced per billing cycle. + """ - currency: Required[str] - """An ISO 4217 currency string for which this price is billed in.""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - item_id: Required[str] - """The id of the item the plan will be associated with.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - model_type: Required[Literal["tiered_package_with_minimum"]] + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - name: Required[str] - """The name of the price.""" - tiered_package_with_minimum_config: Required[Dict[str, object]] +class AddPriceNewFloatingEventOutputPriceEventOutputConfig(TypedDict, total=False): + """Configuration for event_output pricing""" - billable_metric_id: Optional[str] - """The id of the billable metric for the price. + unit_rating_key: Required[str] + """The key in the event data to extract the unit rate from.""" - Only needed if the price is usage-based. + default_unit_rate: Optional[str] """ - - 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. + If provided, this amount will be used as the unit rate when an event does not + have a value for the `unit_rating_key`. If not provided, events missing a unit + rate will be ignored. """ - external_price_id: Optional[str] - """An alias for the price.""" + grouping_key: Optional[str] + """An optional key in the event data to group by (e.g., event ID). - fixed_price_quantity: Optional[float] - """ - If the Price represents a fixed cost, this represents the quantity of units - applied. + All events will also be grouped by their unit rate. """ - invoice_grouping_key: Optional[str] - """The property used to group this price on an invoice""" +AddPriceNewFloatingEventOutputPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] -class AddPriceNewFloatingUnitWithPercentPrice(TypedDict, total=False): - cadence: Required[Literal["annual", "monthly", "quarterly", "one_time"]] + +class AddPriceNewFloatingEventOutputPrice(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.""" + event_output_config: Required[AddPriceNewFloatingEventOutputPriceEventOutputConfig] + """Configuration for event_output pricing""" + item_id: Required[str] - """The id of the item the plan will be associated with.""" + """The id of the item the price will be associated with.""" - model_type: Required[Literal["unit_with_percent"]] + model_type: Required[Literal["event_output"]] + """The pricing model type""" 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. @@ -863,6 +1001,21 @@ class AddPriceNewFloatingUnitWithPercentPrice(TypedDict, total=False): this is true, and in-arrears if this is false. """ + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPriceNewFloatingEventOutputPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + external_price_id: Optional[str] """An alias for the price.""" @@ -875,41 +1028,84 @@ class AddPriceNewFloatingUnitWithPercentPrice(TypedDict, total=False): invoice_grouping_key: Optional[str] """The property used to group this price on an invoice""" - -AddPrice = Union[ - AddPriceNewFloatingUnitPrice, - AddPriceNewFloatingPackagePrice, - AddPriceNewFloatingMatrixPrice, - AddPriceNewFloatingMatrixWithAllocationPrice, - AddPriceNewFloatingTieredPrice, - AddPriceNewFloatingTieredBpsPrice, - AddPriceNewFloatingBpsPrice, - AddPriceNewFloatingBulkBpsPrice, - AddPriceNewFloatingBulkPrice, - AddPriceNewFloatingThresholdTotalAmountPrice, - AddPriceNewFloatingTieredPackagePrice, - AddPriceNewFloatingTieredWithMinimumPrice, - AddPriceNewFloatingPackageWithAllocationPrice, - AddPriceNewFloatingTieredPackageWithMinimumPrice, - AddPriceNewFloatingUnitWithPercentPrice, + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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`. + """ + + +AddPrice: TypeAlias = Union[ + NewFloatingUnitPrice, + NewFloatingTieredPrice, + NewFloatingBulkPrice, + AddPriceNewFloatingBulkWithFiltersPrice, + NewFloatingPackagePrice, + NewFloatingMatrixPrice, + NewFloatingThresholdTotalAmountPrice, + NewFloatingTieredPackagePrice, + NewFloatingTieredWithMinimumPrice, + NewFloatingGroupedTieredPrice, + NewFloatingTieredPackageWithMinimumPrice, + NewFloatingPackageWithAllocationPrice, + NewFloatingUnitWithPercentPrice, + NewFloatingMatrixWithAllocationPrice, + AddPriceNewFloatingMatrixWithThresholdDiscountsPrice, + NewFloatingTieredWithProrationPrice, + NewFloatingUnitWithProrationPrice, + NewFloatingGroupedAllocationPrice, + NewFloatingBulkWithProrationPrice, + NewFloatingGroupedWithProratedMinimumPrice, + NewFloatingGroupedWithMeteredMinimumPrice, + AddPriceNewFloatingGroupedWithMinMaxThresholdsPrice, + NewFloatingMatrixWithDisplayNamePrice, + NewFloatingGroupedTieredPackagePrice, + NewFloatingMaxGroupTieredPackagePrice, + NewFloatingScalableMatrixWithUnitPricingPrice, + NewFloatingScalableMatrixWithTieredPricingPrice, + NewFloatingCumulativeGroupedBulkPrice, + AddPriceNewFloatingCumulativeGroupedAllocationPrice, + AddPriceNewFloatingDailyCreditAllowancePrice, + AddPriceNewFloatingMeteredAllowancePrice, + NewFloatingMinimumCompositePrice, + AddPriceNewFloatingPercentCompositePrice, + AddPriceNewFloatingEventOutputPrice, ] class Add(TypedDict, total=False): start_date: Required[ - Annotated[Union[Union[str, datetime], Literal["start_of_term", "end_of_term"]], PropertyInfo(format="iso8601")] + Annotated[Union[Union[str, datetime], BillingCycleRelativeDate], PropertyInfo(format="iso8601")] ] """The start date of the price interval. This is the date that the price will start billing on the subscription. """ + allocation_price: Optional[NewAllocationPrice] + """The definition of a new allocation price to create and add to the subscription.""" + + can_defer_billing: Optional[bool] + """ + If true, an in-arrears price interval ending mid-cycle will defer billing the + final line item until the next scheduled invoice. If false, it will be billed on + its end date. + """ + discounts: Optional[Iterable[AddDiscount]] """A list of discounts to initialize on the price interval.""" - end_date: Annotated[ - Union[Union[str, datetime], Literal["start_of_term", "end_of_term"], None], PropertyInfo(format="iso8601") - ] + end_date: Annotated[Union[Union[str, datetime], BillingCycleRelativeDate, None], PropertyInfo(format="iso8601")] """The end date of the price interval. This is the date that the price will stop billing on the subscription. @@ -918,6 +1114,14 @@ class Add(TypedDict, total=False): external_price_id: Optional[str] """The external price id of the price to add to the subscription.""" + filter: Optional[str] + """An additional filter to apply to usage queries. + + This filter must be expressed as a boolean + [computed property](/extensibility/advanced-metrics#computed-properties). If + null, usage queries will not include any additional filter. + """ + fixed_fee_quantity_transitions: Optional[Iterable[AddFixedFeeQuantityTransition]] """A list of fixed fee quantity transitions to initialize on the price interval.""" @@ -927,6 +1131,12 @@ class Add(TypedDict, total=False): billing period. """ + metric_parameter_overrides: Optional[Dict[str, object]] + """Override values for parameterized billable metric variables. + + Keys are parameter names, values are the override values (number or string). + """ + minimum_amount: Optional[float] """ The minimum amount that will be billed for this price interval for a given @@ -934,11 +1144,115 @@ class Add(TypedDict, total=False): """ price: Optional[AddPrice] - """The definition of a new price to create and add to the subscription.""" + """New floating price request body params.""" price_id: Optional[str] """The id of the price to add to the subscription.""" + usage_customer_ids: Optional[SequenceNotStr[str]] + """ + A list of customer IDs whose usage events will be aggregated and billed under + this subscription. By default, a subscription only considers usage events + associated with its attached customer's customer_id. When usage_customer_ids is + provided, the subscription includes usage events from the specified customers + only. Provided usage_customer_ids must be either the customer for this + subscription itself, or any of that customer's children. + """ + + +class AddAdjustmentAdjustmentNewTieredPercentageDiscountTier(TypedDict, total=False): + lower_bound: Required[float] + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: Required[float] + """The percentage (0-1) discounted from spend in this tier.""" + + upper_bound: Optional[float] + """Inclusive upper bound of cumulative spend; null for the final open-ended tier.""" + + +class AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class AddAdjustmentAdjustmentNewTieredPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["tiered_percentage_discount"]] + + tiers: Required[Iterable[AddAdjustmentAdjustmentNewTieredPercentageDiscountTier]] + + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[Iterable[AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter]] + """A list of filters that determine which prices this adjustment will apply to.""" + + 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. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" + + +AddAdjustmentAdjustment: TypeAlias = Union[ + NewPercentageDiscount, + NewUsageDiscount, + NewAmountDiscount, + NewMinimum, + NewMaximum, + AddAdjustmentAdjustmentNewTieredPercentageDiscount, +] + + +class AddAdjustment(TypedDict, total=False): + start_date: Required[ + Annotated[Union[Union[str, datetime], BillingCycleRelativeDate], PropertyInfo(format="iso8601")] + ] + """The start date of the adjustment interval. + + This is the date that the adjustment will start affecting prices on the + subscription. The adjustment will apply to invoice dates that overlap with this + `start_date`. This `start_date` is treated as inclusive for in-advance prices, + and exclusive for in-arrears prices. + """ + + adjustment: Optional[AddAdjustmentAdjustment] + """The definition of a new adjustment to create and add to the subscription.""" + + adjustment_id: Optional[str] + """The ID of the adjustment to add to the subscription. + + Adjustment IDs can be re-used from existing subscriptions or plans, but + adjustments associated with coupon redemptions cannot be re-used. + """ + + end_date: Annotated[Union[Union[str, datetime], BillingCycleRelativeDate, 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. The adjustment will apply to invoice dates that overlap with this + `end_date`.This `end_date` is treated as exclusive for in-advance prices, and + inclusive for in-arrears prices. + """ + class EditFixedFeeQuantityTransition(TypedDict, total=False): effective_date: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] @@ -959,12 +1273,25 @@ class Edit(TypedDict, total=False): overlapping price intervals must have the same billing cycle day. """ - end_date: Annotated[ - Union[Union[str, datetime], Literal["start_of_term", "end_of_term"], None], PropertyInfo(format="iso8601") - ] + can_defer_billing: Optional[bool] + """ + If true, an in-arrears price interval ending mid-cycle will defer billing the + final line item until the next scheduled invoice. If false, it will be billed on + its end date. + """ + + end_date: Annotated[Union[Union[str, datetime], BillingCycleRelativeDate, None], PropertyInfo(format="iso8601")] """The updated end date of this price interval. - If not specified, the start date will not be updated. + If not specified, the end date will not be updated. + """ + + filter: Optional[str] + """An additional filter to apply to usage queries. + + This filter must be expressed as a boolean + [computed property](/extensibility/advanced-metrics#computed-properties). If + null, usage queries will not include any additional filter. """ fixed_fee_quantity_transitions: Optional[Iterable[EditFixedFeeQuantityTransition]] @@ -974,10 +1301,41 @@ class Edit(TypedDict, total=False): on the price interval. """ - start_date: Annotated[ - Union[Union[str, datetime], Literal["start_of_term", "end_of_term"]], PropertyInfo(format="iso8601") - ] + metric_parameter_overrides: Optional[Dict[str, object]] + """Override values for parameterized billable metric variables. + + Keys are parameter names, values are the override values (number or string). + """ + + start_date: Annotated[Union[Union[str, datetime], BillingCycleRelativeDate], PropertyInfo(format="iso8601")] """The updated start date of this price interval. If not specified, the start date will not be updated. """ + + usage_customer_ids: Optional[SequenceNotStr[str]] + """ + A list of customer IDs whose usage events will be aggregated and billed under + this subscription. By default, a subscription only considers usage events + associated with its attached customer's customer_id. When usage_customer_ids is + provided, the subscription includes usage events from the specified customers + only. Provided usage_customer_ids must be either the customer for this + subscription itself, or any of that customer's children. + """ + + +class EditAdjustment(TypedDict, total=False): + adjustment_interval_id: Required[str] + """The id of the adjustment interval to edit.""" + + end_date: Annotated[Union[Union[str, datetime], BillingCycleRelativeDate, None], PropertyInfo(format="iso8601")] + """The updated end date of this adjustment interval. + + If not specified, the end date will not be updated. + """ + + start_date: Annotated[Union[Union[str, datetime], BillingCycleRelativeDate], PropertyInfo(format="iso8601")] + """The updated start date of this adjustment interval. + + If not specified, the start date will not be updated. + """ diff --git a/src/orb/types/subscription_redeem_coupon_params.py b/src/orb/types/subscription_redeem_coupon_params.py new file mode 100644 index 00000000..3b4e9878 --- /dev/null +++ b/src/orb/types/subscription_redeem_coupon_params.py @@ -0,0 +1,34 @@ +# 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 Literal, Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["SubscriptionRedeemCouponParams"] + + +class SubscriptionRedeemCouponParams(TypedDict, total=False): + change_option: Required[Literal["requested_date", "end_of_subscription_term", "immediate"]] + + allow_invoice_credit_or_void: Optional[bool] + """ + If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + """ + + change_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The date that the coupon discount should take effect. + + This parameter can only be passed if the `change_option` is `requested_date`. + """ + + coupon_id: Optional[str] + """Coupon ID to be redeemed for this subscription.""" + + coupon_redemption_code: Optional[str] + """Redemption code of the coupon to be redeemed for this subscription.""" diff --git a/src/orb/types/subscription_schedule_plan_change_params.py b/src/orb/types/subscription_schedule_plan_change_params.py index ce484cfc..fe9d82b7 100644 --- a/src/orb/types/subscription_schedule_plan_change_params.py +++ b/src/orb/types/subscription_schedule_plan_change_params.py @@ -2,91 +2,231 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict +from typing import Dict, Union, Iterable, Optional +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .._utils import PropertyInfo +from .discount_override_param import DiscountOverrideParam +from .shared_params.new_maximum import NewMaximum +from .shared_params.new_minimum import NewMinimum +from .shared_params.new_usage_discount import NewUsageDiscount +from .new_subscription_bulk_price_param import NewSubscriptionBulkPriceParam +from .new_subscription_unit_price_param import NewSubscriptionUnitPriceParam +from .shared_params.new_amount_discount import NewAmountDiscount +from .shared_params.new_allocation_price import NewAllocationPrice +from .new_subscription_matrix_price_param import NewSubscriptionMatrixPriceParam +from .new_subscription_tiered_price_param import NewSubscriptionTieredPriceParam +from .new_subscription_package_price_param import NewSubscriptionPackagePriceParam +from .shared_params.new_percentage_discount import NewPercentageDiscount +from .shared_params.unit_conversion_rate_config import UnitConversionRateConfig +from .new_subscription_grouped_tiered_price_param import NewSubscriptionGroupedTieredPriceParam +from .new_subscription_tiered_package_price_param import NewSubscriptionTieredPackagePriceParam +from .shared_params.tiered_conversion_rate_config import TieredConversionRateConfig +from .shared_params.new_billing_cycle_configuration import NewBillingCycleConfiguration +from .new_subscription_minimum_composite_price_param import NewSubscriptionMinimumCompositePriceParam +from .new_subscription_unit_with_percent_price_param import NewSubscriptionUnitWithPercentPriceParam +from .new_subscription_grouped_allocation_price_param import NewSubscriptionGroupedAllocationPriceParam +from .new_subscription_bulk_with_proration_price_param import NewSubscriptionBulkWithProrationPriceParam +from .new_subscription_tiered_with_minimum_price_param import NewSubscriptionTieredWithMinimumPriceParam +from .new_subscription_unit_with_proration_price_param import NewSubscriptionUnitWithProrationPriceParam +from .shared_params.billing_cycle_anchor_configuration import BillingCycleAnchorConfiguration +from .shared_params.new_dimensional_price_configuration import NewDimensionalPriceConfiguration +from .new_subscription_grouped_tiered_package_price_param import NewSubscriptionGroupedTieredPackagePriceParam +from .new_subscription_matrix_with_allocation_price_param import NewSubscriptionMatrixWithAllocationPriceParam +from .new_subscription_threshold_total_amount_price_param import NewSubscriptionThresholdTotalAmountPriceParam +from .new_subscription_cumulative_grouped_bulk_price_param import NewSubscriptionCumulativeGroupedBulkPriceParam +from .new_subscription_package_with_allocation_price_param import NewSubscriptionPackageWithAllocationPriceParam +from .new_subscription_matrix_with_display_name_price_param import NewSubscriptionMatrixWithDisplayNamePriceParam +from .new_subscription_max_group_tiered_package_price_param import NewSubscriptionMaxGroupTieredPackagePriceParam +from .new_subscription_tiered_package_with_minimum_price_param import NewSubscriptionTieredPackageWithMinimumPriceParam +from .new_subscription_grouped_with_metered_minimum_price_param import ( + NewSubscriptionGroupedWithMeteredMinimumPriceParam, +) +from .new_subscription_grouped_with_prorated_minimum_price_param import ( + NewSubscriptionGroupedWithProratedMinimumPriceParam, +) +from .new_subscription_scalable_matrix_with_unit_pricing_price_param import ( + NewSubscriptionScalableMatrixWithUnitPricingPriceParam, +) +from .new_subscription_scalable_matrix_with_tiered_pricing_price_param import ( + NewSubscriptionScalableMatrixWithTieredPricingPriceParam, +) __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", + "AddAdjustment", + "AddAdjustmentAdjustment", + "AddAdjustmentAdjustmentNewTieredPercentageDiscount", + "AddAdjustmentAdjustmentNewTieredPercentageDiscountTier", + "AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter", + "AddPrice", + "AddPricePrice", + "AddPricePriceNewSubscriptionBulkWithFiltersPrice", + "AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfig", + "AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigFilter", + "AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigTier", + "AddPricePriceNewSubscriptionBulkWithFiltersPriceConversionRateConfig", + "AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPrice", + "AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig", + "AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue", + "AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup", + "AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceConversionRateConfig", + "AddPricePriceNewSubscriptionTieredWithProrationPrice", + "AddPricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfig", + "AddPricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfigTier", + "AddPricePriceNewSubscriptionTieredWithProrationPriceConversionRateConfig", + "AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPrice", + "AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig", + "AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceConversionRateConfig", + "AddPricePriceNewSubscriptionCumulativeGroupedAllocationPrice", + "AddPricePriceNewSubscriptionCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig", + "AddPricePriceNewSubscriptionCumulativeGroupedAllocationPriceConversionRateConfig", + "AddPricePriceNewSubscriptionDailyCreditAllowancePrice", + "AddPricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfig", + "AddPricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue", + "AddPricePriceNewSubscriptionDailyCreditAllowancePriceConversionRateConfig", + "AddPricePriceNewSubscriptionMeteredAllowancePrice", + "AddPricePriceNewSubscriptionMeteredAllowancePriceMeteredAllowanceConfig", + "AddPricePriceNewSubscriptionMeteredAllowancePriceConversionRateConfig", + "AddPricePriceNewSubscriptionPercentCompositePrice", + "AddPricePriceNewSubscriptionPercentCompositePricePercentConfig", + "AddPricePriceNewSubscriptionPercentCompositePriceConversionRateConfig", + "AddPricePriceNewSubscriptionEventOutputPrice", + "AddPricePriceNewSubscriptionEventOutputPriceEventOutputConfig", + "AddPricePriceNewSubscriptionEventOutputPriceConversionRateConfig", + "RemoveAdjustment", + "RemovePrice", + "ReplaceAdjustment", + "ReplaceAdjustmentAdjustment", + "ReplaceAdjustmentAdjustmentNewTieredPercentageDiscount", + "ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountTier", + "ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountFilter", + "ReplacePrice", + "ReplacePricePrice", + "ReplacePricePriceNewSubscriptionBulkWithFiltersPrice", + "ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfig", + "ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigFilter", + "ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigTier", + "ReplacePricePriceNewSubscriptionBulkWithFiltersPriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPrice", + "ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig", + "ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue", + "ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup", + "ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionTieredWithProrationPrice", + "ReplacePricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfig", + "ReplacePricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfigTier", + "ReplacePricePriceNewSubscriptionTieredWithProrationPriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPrice", + "ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig", + "ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPrice", + "ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig", + "ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionDailyCreditAllowancePrice", + "ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfig", + "ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue", + "ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionMeteredAllowancePrice", + "ReplacePricePriceNewSubscriptionMeteredAllowancePriceMeteredAllowanceConfig", + "ReplacePricePriceNewSubscriptionMeteredAllowancePriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionPercentCompositePrice", + "ReplacePricePriceNewSubscriptionPercentCompositePricePercentConfig", + "ReplacePricePriceNewSubscriptionPercentCompositePriceConversionRateConfig", + "ReplacePricePriceNewSubscriptionEventOutputPrice", + "ReplacePricePriceNewSubscriptionEventOutputPriceEventOutputConfig", + "ReplacePricePriceNewSubscriptionEventOutputPriceConversionRateConfig", ] 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. - Reset billing periods to be aligned with the plan change’s effective date. + Reset billing periods to be aligned with the plan change's effective date. + """ + + auto_collection: Optional[bool] + """ + 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. + """ + + auto_issuance: Optional[bool] + """Used to determine if invoices for this subscription will be automatically + issued. + + If true, invoices will be automatically issued. If false, invoices will require + manual approval. If `null` is specified, this defaults to the behavior + configured for this customer. """ billing_cycle_alignment: Optional[Literal["unchanged", "plan_change_date", "start_of_month"]] """ - Reset billing periods to be aligned with the plan change’s effective date or + Reset billing periods to be aligned with the plan change's effective date or start of the month. Defaults to `unchanged` which keeps subscription's existing billing cycle alignment. """ - change_date: Optional[str] + 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. - This parameter can only be passed if the `change_option` is `requested_date`. + This parameter can only be passed if the `change_option` is `requested_date`. If + a date with no time is passed, the plan change will happen at midnight in the + customer's timezone. """ coupon_redemption_code: Optional[str] """Redemption code to be used for this subscription. If the coupon cannot be found by its redemption code, or cannot be redeemed, an - error response will be returned and the plan change will not be scheduled. + error response will be returned and the subscription creation or plan change + will not be scheduled. """ credits_overage_rate: Optional[float] + default_invoice_memo: Optional[str] + """Determines the default memo on this subscription's invoices. + + Note that if this is not provided, it is determined by the plan configuration. + """ + external_plan_id: Optional[str] """ 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: Optional[str] + """An additional filter to apply to usage queries. + + This filter must be expressed as a boolean + [computed property](/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""" @@ -97,7 +237,14 @@ class SubscriptionSchedulePlanChangeParams(TypedDict, total=False): at the end of the billing period. """ - per_credit_overage_amount: Optional[str] + net_terms: Optional[int] + """ + The net terms determines the difference between the invoice date and the issue + date for the invoice. If you intend the invoice to be due on issue, set this + to 0. If not provided, this defaults to the value specified in the plan. + """ + + per_credit_overage_amount: Optional[float] plan_id: Optional[str] """The plan that the given subscription should be switched to. @@ -105,764 +252,2553 @@ class SubscriptionSchedulePlanChangeParams(TypedDict, total=False): Note that either this property or `external_plan_id` must be specified. """ - price_overrides: Optional[Iterable[PriceOverride]] - """Optionally provide a list of overrides for prices on the plan""" + 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""" -class PriceOverrideOverrideUnitPriceUnitConfig(TypedDict, total=False): - unit_amount: Required[str] - """Rate per unit of usage""" + 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) + """ -class PriceOverrideOverrideUnitPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + remove_prices: Optional[Iterable[RemovePrice]] + """Plan prices to be removed from the subscription. - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + (Only available for accounts that have migrated off of legacy subscription + overrides) + """ - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + replace_adjustments: Optional[Iterable[ReplaceAdjustment]] + """Plan adjustments to be replaced with additional adjustments on the subscription. - For plan/plan phase discounts, this can be a subset of prices. + (Only available for accounts that have migrated off of legacy subscription + overrides) """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + replace_prices: Optional[Iterable[ReplacePrice]] + """Plan prices to be replaced with additional prices on the subscription. - This is a number between 0 and 1. + (Only available for accounts that have migrated off of legacy subscription + overrides) """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + trial_duration_days: Optional[int] + """The duration of the trial period in days. - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + If not provided, this defaults to the value specified in the plan. If `0` is + provided, the trial on the plan will be skipped. + """ - Number of usage units that this discount is for + usage_customer_ids: Optional[SequenceNotStr[str]] + """ + A list of customer IDs whose usage events will be aggregated and billed under + this subscription. By default, a subscription only considers usage events + associated with its attached customer's customer_id. When usage_customer_ids is + provided, the subscription includes usage events from the specified customers + only. Provided usage_customer_ids must be either the customer for this + subscription itself, or any of that customer's children. """ -class PriceOverrideOverrideUnitPrice(TypedDict, total=False): - id: Required[str] +class AddAdjustmentAdjustmentNewTieredPercentageDiscountTier(TypedDict, total=False): + lower_bound: Required[float] + """Exclusive lower bound of cumulative spend for this tier.""" - model_type: Required[Literal["unit"]] + percentage: Required[float] + """The percentage (0-1) discounted from spend in this tier.""" - unit_config: Required[PriceOverrideOverrideUnitPriceUnitConfig] + upper_bound: Optional[float] + """Inclusive upper bound of cumulative spend; null for the final open-ended tier.""" - discount: Optional[PriceOverrideOverrideUnitPriceDiscount] - """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 AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" -class PriceOverrideOverridePackagePricePackageConfig(TypedDict, total=False): - package_amount: Required[str] - """A currency amount to rate usage by""" +class AddAdjustmentAdjustmentNewTieredPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["tiered_percentage_discount"]] - package_size: Optional[int] - """An integer amount to represent package size. + tiers: Required[Iterable[AddAdjustmentAdjustmentNewTieredPercentageDiscountTier]] - For example, 1000 here would divide usage by 1000 before multiplying by - package_amount in rating - """ + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" -class PriceOverrideOverridePackagePriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + filters: Optional[Iterable[AddAdjustmentAdjustmentNewTieredPercentageDiscountFilter]] + """A list of filters that determine which prices this adjustment will apply to.""" - 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. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" + + +AddAdjustmentAdjustment: TypeAlias = Union[ + NewPercentageDiscount, + NewUsageDiscount, + NewAmountDiscount, + NewMinimum, + NewMaximum, + AddAdjustmentAdjustmentNewTieredPercentageDiscount, +] + - This is a number between 0 and 1. +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. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + plan_phase_order: Optional[int] + """The phase to add this adjustment to.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + start_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The start date of the adjustment interval. - Number of usage units that this discount is for + 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 PriceOverrideOverridePackagePrice(TypedDict, total=False): - id: Required[str] +class AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigFilter(TypedDict, total=False): + """Configuration for a single property filter""" - model_type: Required[Literal["package"]] + property_key: Required[str] + """Event property key to filter on""" - package_config: Required[PriceOverrideOverridePackagePricePackageConfig] + property_value: Required[str] + """Event property value to match""" - discount: Optional[PriceOverrideOverridePackagePriceDiscount] - """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 AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier""" - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + unit_amount: Required[str] + """Amount per unit""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + tier_lower_bound: Optional[str] + """The lower bound for this tier""" -class PriceOverrideOverrideMatrixPriceMatrixConfigMatrixValue(TypedDict, total=False): - dimension_values: Required[List[Optional[str]]] - """One or two matrix keys to filter usage to this Matrix value by. +class AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfig(TypedDict, total=False): + """Configuration for bulk_with_filters pricing""" - For example, ["region", "tier"] could be used to filter cloud usage by a cloud - region and an instance tier. - """ + filters: Required[Iterable[AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigFilter]] + """Property filters to apply (all must match)""" - unit_amount: Required[str] - """Unit price for the specified dimension_values""" + tiers: Required[Iterable[AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigTier]] + """Bulk tiers for rating based on total usage volume""" -class PriceOverrideOverrideMatrixPriceMatrixConfig(TypedDict, total=False): - default_unit_amount: Required[str] - """Default per unit rate for any usage not bucketed into a specified matrix_value""" +AddPricePriceNewSubscriptionBulkWithFiltersPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] - dimensions: Required[List[Optional[str]]] - """One or two event property values to evaluate matrix groups by""" - matrix_values: Required[Iterable[PriceOverrideOverrideMatrixPriceMatrixConfigMatrixValue]] - """Matrix values for specified matrix grouping keys""" +class AddPricePriceNewSubscriptionBulkWithFiltersPrice(TypedDict, total=False): + bulk_with_filters_config: Required[AddPricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfig] + """Configuration for bulk_with_filters pricing""" + + 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 price will be associated with.""" -class PriceOverrideOverrideMatrixPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + model_type: Required[Literal["bulk_with_filters"]] + """The pricing model type""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + name: Required[str] + """The name of the price.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - For plan/plan phase discounts, this can be a subset of prices. + 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[NewBillingCycleConfiguration] + """ + 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`. + conversion_rate_config: Optional[AddPricePriceNewSubscriptionBulkWithFiltersPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" - Number of usage units that this discount is for + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" -class PriceOverrideOverrideMatrixPrice(TypedDict, total=False): - id: Required[str] - - matrix_config: Required[PriceOverrideOverrideMatrixPriceMatrixConfig] + external_price_id: Optional[str] + """An alias for the price.""" - model_type: Required[Literal["matrix"]] + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - discount: Optional[PriceOverrideOverrideMatrixPriceDiscount] - """The subscription's override discount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + If unspecified, a single invoice is produced per billing cycle. + """ - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. -class PriceOverrideOverrideTieredPriceTieredConfigTier(TypedDict, total=False): - first_unit: Required[float] - """Inclusive tier starting value""" + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - unit_amount: Required[str] - """Amount per unit""" + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ - last_unit: Optional[float] - """Exclusive tier ending value. If null, this is treated as the last tier""" +class AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue( + TypedDict, total=False +): + first_dimension_value: Required[str] -class PriceOverrideOverrideTieredPriceTieredConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideTieredPriceTieredConfigTier]] - """Tiers for rating based on total usage quantities into the specified tier""" + unit_amount: Required[str] + second_dimension_value: Optional[str] -class PriceOverrideOverrideTieredPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" +class AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup( + TypedDict, total=False +): + above_threshold_discount_percentage: Required[str] + """Discount rate applied to spend above the threshold.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + below_threshold_discount_percentage: Required[str] + """Discount rate applied to spend at or below the threshold. - For plan/plan phase discounts, this can be a subset of prices. + Set to 0 for no baseline discount. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + cell_coordinates: Required[str] + """Semicolon-separated list of matrix cell coordinates targeted by this group. - This is a number between 0 and 1. + Each coordinate is `first,second` when the matrix has two dimensions, or just + `first` for a single-dimension matrix. Example: `blue,circle;green,triangle`. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + threshold_amount: Required[str] - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + description: Optional[str] - Number of usage units that this discount is for - """ +class AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig( + TypedDict, total=False +): + """Configuration for matrix_with_threshold_discounts pricing""" -class PriceOverrideOverrideTieredPrice(TypedDict, total=False): - id: Required[str] + default_unit_amount: Required[str] + """Unit price used for usage that does not match any defined matrix cell.""" - model_type: Required[Literal["tiered"]] + first_dimension: Required[str] + """First matrix dimension key.""" - tiered_config: Required[PriceOverrideOverrideTieredPriceTieredConfig] + matrix_values: Required[ + Iterable[ + AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue + ] + ] + """Per-cell unit prices.""" - discount: Optional[PriceOverrideOverrideTieredPriceDiscount] - """The subscription's override discount for the plan.""" + second_dimension: Optional[str] + """Optional second matrix dimension key.""" - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + threshold_discount_groups: Iterable[ + AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup + ] - 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.""" +AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] -class PriceOverrideOverrideTieredBpsPriceTieredBpsConfigTier(TypedDict, total=False): - bps: Required[float] - """Per-event basis point rate""" +class AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - minimum_amount: Required[str] - """Inclusive tier starting value""" + item_id: Required[str] + """The id of the item the price will be associated with.""" - maximum_amount: Optional[str] - """Exclusive tier ending value""" + matrix_with_threshold_discounts_config: Required[ + AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + ] + """Configuration for matrix_with_threshold_discounts pricing""" + + model_type: Required[Literal["matrix_with_threshold_discounts"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - per_unit_maximum: Optional[str] - """Per unit maximum to charge""" + 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 PriceOverrideOverrideTieredBpsPriceTieredBpsConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideTieredBpsPriceTieredBpsConfigTier]] + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] """ - Tiers for a Graduated BPS pricing model, where usage is bucketed into specified - tiers + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" -class PriceOverrideOverrideTieredBpsPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + external_price_id: Optional[str] + """An alias for the price.""" - For plan/plan phase discounts, this can be a subset of prices. + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - This is a number between 0 and 1. + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - 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 PriceOverrideOverrideTieredBpsPrice(TypedDict, total=False): - id: Required[str] +class AddPricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single tiered with proration tier""" - model_type: Required[Literal["tiered_bps"]] + tier_lower_bound: Required[str] + """Inclusive tier starting value""" - tiered_bps_config: Required[PriceOverrideOverrideTieredBpsPriceTieredBpsConfig] + unit_amount: Required[str] + """Amount per unit""" - discount: Optional[PriceOverrideOverrideTieredBpsPriceDiscount] - """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 AddPricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfig(TypedDict, total=False): + """Configuration for tiered_with_proration pricing""" - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + tiers: Required[Iterable[AddPricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfigTier]] + """ + Tiers for rating based on total usage quantities into the specified tier with + proration + """ - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" +AddPricePriceNewSubscriptionTieredWithProrationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewSubscriptionTieredWithProrationPrice(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 price will be associated with.""" -class PriceOverrideOverrideBpsPriceBpsConfig(TypedDict, total=False): - bps: Required[float] - """Basis point take rate per event""" + model_type: Required[Literal["tiered_with_proration"]] + """The pricing model type""" - per_unit_maximum: Optional[str] - """Optional currency amount maximum to cap spend per event""" + name: Required[str] + """The name of the price.""" + tiered_with_proration_config: Required[ + AddPricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfig + ] + """Configuration for tiered_with_proration pricing""" -class PriceOverrideOverrideBpsPriceDiscount(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[NewBillingCycleConfiguration] + """ + 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. + conversion_rate_config: Optional[AddPricePriceNewSubscriptionTieredWithProrationPriceConversionRateConfig] + """The configuration for the 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. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" - 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 PriceOverrideOverrideBpsPrice(TypedDict, total=False): - id: Required[str] + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. - bps_config: Required[PriceOverrideOverrideBpsPriceBpsConfig] + If unspecified, a single invoice is produced per billing cycle. + """ - model_type: Required[Literal["bps"]] + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - discount: Optional[PriceOverrideOverrideBpsPriceDiscount] - """The subscription's override discount for the plan.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed 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`. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" +class AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig( + TypedDict, total=False +): + """Configuration for grouped_with_min_max_thresholds pricing""" -class PriceOverrideOverrideBulkBpsPriceBulkBpsConfigTier(TypedDict, total=False): - bps: Required[float] - """Basis points to rate on""" + grouping_key: Required[str] + """The event property used to group before applying thresholds""" - maximum_amount: Optional[str] - """Upper bound for tier""" + maximum_charge: Required[str] + """The maximum amount to charge each group""" - per_unit_maximum: Optional[str] - """The maximum amount to charge for any one event""" + minimum_charge: Required[str] + """The minimum amount to charge each group, regardless of usage""" + per_unit_rate: Required[str] + """The base price charged per group""" -class PriceOverrideOverrideBulkBpsPriceBulkBpsConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideBulkBpsPriceBulkBpsConfigTier]] - """ - Tiers for a bulk BPS pricing model where all usage is aggregated to a single - tier based on total volume + +AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_with_min_max_thresholds_config: Required[ + AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + ] + """Configuration for grouped_with_min_max_thresholds pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_min_max_thresholds"]] + """The pricing model type""" + + 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. + """ -class PriceOverrideOverrideBulkBpsPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + conversion_rate_config: Optional[AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" - For plan/plan phase discounts, this can be a subset of prices. + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" - This is a number between 0 and 1. + 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. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. - Number of usage units that this discount is for + If unspecified, a single invoice is produced per billing cycle. """ + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" -class PriceOverrideOverrideBulkBpsPrice(TypedDict, total=False): - id: Required[str] + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - bulk_bps_config: Required[PriceOverrideOverrideBulkBpsPriceBulkBpsConfig] + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - model_type: Required[Literal["bulk_bps"]] + 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[PriceOverrideOverrideBulkBpsPriceDiscount] - """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 AddPricePriceNewSubscriptionCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig( + TypedDict, total=False +): + """Configuration for cumulative_grouped_allocation pricing""" - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + cumulative_allocation: Required[str] + """The overall allocation across all groups""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + group_allocation: Required[str] + """The allocation per individual group""" + grouping_key: Required[str] + """The event property used to group usage before applying allocations""" -class PriceOverrideOverrideBulkPriceBulkConfigTier(TypedDict, total=False): unit_amount: Required[str] - """Amount per unit""" + """The amount to charge for each unit outside of the allocation""" - maximum_units: Optional[float] - """Upper bound for this tier""" +AddPricePriceNewSubscriptionCumulativeGroupedAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] -class PriceOverrideOverrideBulkPriceBulkConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideBulkPriceBulkConfigTier]] - """Bulk tiers for rating based on total usage volume""" +class AddPricePriceNewSubscriptionCumulativeGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" -class PriceOverrideOverrideBulkPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + cumulative_grouped_allocation_config: Required[ + AddPricePriceNewSubscriptionCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + ] + """Configuration for cumulative_grouped_allocation pricing""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + item_id: Required[str] + """The id of the item the price will be associated with.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + model_type: Required[Literal["cumulative_grouped_allocation"]] + """The pricing model type""" - For plan/plan phase discounts, this can be a subset of prices. - """ + name: Required[str] + """The name of the price.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - This is a number between 0 and 1. + Only needed if the price is usage-based. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" - - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + 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. + """ - Number of usage units that this discount is for + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + 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.""" -class PriceOverrideOverrideBulkPrice(TypedDict, total=False): - id: Required[str] + conversion_rate_config: Optional[AddPricePriceNewSubscriptionCumulativeGroupedAllocationPriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" - bulk_config: Required[PriceOverrideOverrideBulkPriceBulkConfig] + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ - model_type: Required[Literal["bulk"]] + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" - 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.""" + """ + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + If unspecified, a single invoice is produced per billing cycle. + """ -class PriceOverrideOverrideThresholdTotalAmountPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - 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 AddPricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue( + TypedDict, total=False +): + """Per-dimension credit price for the daily credit allowance model.""" + + dimension_values: Required[SequenceNotStr[Optional[str]]] + """One or two matrix keys to filter usage to this value by. + + For example, ["model"] could be used to apply a different credit rate to each AI + model. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + unit_amount: Required[str] + """Credits charged per unit of usage matching the specified dimension_values""" + - usage_discount: Optional[float] - """Only available if discount_type is `usage`. +class AddPricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfig(TypedDict, total=False): + """Configuration for daily_credit_allowance pricing""" - Number of usage units that this discount is for + daily_allowance: Required[str] + """Credits granted per day. Lose-it-or-use-it; does not roll over.""" + + default_unit_amount: Required[str] + """ + Default per-unit credit rate for any usage not bucketed into a specified + matrix_value """ + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" -class PriceOverrideOverrideThresholdTotalAmountPrice(TypedDict, total=False): - id: Required[str] + event_day_property: Required[str] + """Event property whose value identifies the day bucket the event belongs to (e.g. - model_type: Required[Literal["threshold_total_amount"]] + 'event_day' set to an ISO date string in the customer's timezone). The allowance + resets per distinct value of this property. + """ - threshold_total_amount_config: Required[Dict[str, object]] + matrix_values: Required[ + Iterable[AddPricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue] + ] + """Per-dimension credit rates""" - discount: Optional[PriceOverrideOverrideThresholdTotalAmountPriceDiscount] - """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.""" +AddPricePriceNewSubscriptionDailyCreditAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] - 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.""" +class AddPricePriceNewSubscriptionDailyCreditAllowancePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + daily_credit_allowance_config: Required[ + AddPricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfig + ] + """Configuration for daily_credit_allowance pricing""" + item_id: Required[str] + """The id of the item the price will be associated with.""" -class PriceOverrideOverrideTieredPackagePriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + model_type: Required[Literal["daily_credit_allowance"]] + """The pricing model type""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + name: Required[str] + """The name of the price.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - For plan/plan phase discounts, this can be a subset of prices. + 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[NewBillingCycleConfiguration] + """ + 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`. + conversion_rate_config: Optional[AddPricePriceNewSubscriptionDailyCreditAllowancePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" - Number of usage units that this discount is for + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" -class PriceOverrideOverrideTieredPackagePrice(TypedDict, total=False): - id: Required[str] + external_price_id: Optional[str] + """An alias for the price.""" - model_type: Required[Literal["tiered_package"]] + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - tiered_package_config: Required[Dict[str, object]] + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - discount: Optional[PriceOverrideOverrideTieredPackagePriceDiscount] - """The subscription's override discount for the plan.""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + If unspecified, a single invoice is produced per billing cycle. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + 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 PriceOverrideOverrideTieredWithMinimumPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ - 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 AddPricePriceNewSubscriptionMeteredAllowancePriceMeteredAllowanceConfig(TypedDict, total=False): + """Configuration for metered_allowance pricing""" - For plan/plan phase discounts, this can be a subset of prices. + allowance_grouping_value: Required[str] """ + The grouping_key value whose summed quantity represents the allowance for this + period (e.g. 'storage_snapshot' emitting 3 × avg storage). Capped at consumption + — credit can never exceed actual usage. + """ + + consumption_grouping_value: Required[str] + """The grouping_key value whose summed quantity represents consumption (e.g. - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + 'download'). Charged at unit_amount. + """ - This is a number between 0 and 1. + grouping_key: Required[str] + """ + Event property used to partition the metric into consumption and allowance + quantities (e.g. 'event_name'). The metric is queried with this key and the two + values below select which partition is which. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + unit_amount: Required[str] + """Per-unit price applied to gross consumption and to the allowance credit.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + allowance_display_name: str + """Sub-line label for the credit row (e.g. 'Up to 3x free egress').""" - Number of usage units that this discount is for - """ + consumption_display_name: str + """Sub-line label for the gross consumption row (e.g. 'bytes gotten').""" -class PriceOverrideOverrideTieredWithMinimumPrice(TypedDict, total=False): - id: Required[str] +AddPricePriceNewSubscriptionMeteredAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] - model_type: Required[Literal["tiered_with_minimum"]] - tiered_with_minimum_config: Required[Dict[str, object]] +class AddPricePriceNewSubscriptionMeteredAllowancePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - discount: Optional[PriceOverrideOverrideTieredWithMinimumPriceDiscount] - """The subscription's override discount for the plan.""" + item_id: Required[str] + """The id of the item the price will be associated with.""" - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + metered_allowance_config: Required[AddPricePriceNewSubscriptionMeteredAllowancePriceMeteredAllowanceConfig] + """Configuration for metered_allowance pricing""" - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + model_type: Required[Literal["metered_allowance"]] + """The pricing model type""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + 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. + """ -class PriceOverrideOverridePackageWithAllocationPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + billing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + conversion_rate_config: Optional[AddPricePriceNewSubscriptionMeteredAllowancePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" - For plan/plan phase discounts, this can be a subset of prices. + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" - This is a number between 0 and 1. + 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. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. - Number of usage units that this discount is for + If unspecified, a single invoice is produced per billing cycle. """ + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. -class PriceOverrideOverridePackageWithAllocationPrice(TypedDict, total=False): - id: Required[str] + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - model_type: Required[Literal["package_with_allocation"]] + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ - package_with_allocation_config: Required[Dict[str, object]] - discount: Optional[PriceOverrideOverridePackageWithAllocationPriceDiscount] - """The subscription's override discount for the plan.""" +class AddPricePriceNewSubscriptionPercentCompositePricePercentConfig(TypedDict, total=False): + """Configuration for percent pricing""" - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + percent: Required[float] + """Fraction of the component subtotals to charge (0 < percent <= 1).""" maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + """Maximum amount to charge. If unset, the fee has no upper bound.""" minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + """Minimum amount to charge. If unset, the fee is bounded below by 0.""" + + prorated: bool + """If true, the minimum_amount is prorated based on the service period. + + The maximum_amount is an absolute cap (never prorated), and the percent applied + to upstream subtotals is never prorated either. + """ + +AddPricePriceNewSubscriptionPercentCompositePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class AddPricePriceNewSubscriptionPercentCompositePrice(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 price will be associated with.""" -class PriceOverrideOverrideUnitWithPercentPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + model_type: Required[Literal["percent"]] + """The pricing model type""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + name: Required[str] + """The name of the price.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + percent_config: Required[AddPricePriceNewSubscriptionPercentCompositePricePercentConfig] + """Configuration for percent pricing""" - For plan/plan phase discounts, this can be a subset of prices. + 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[NewBillingCycleConfiguration] + """ + 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`. + conversion_rate_config: Optional[AddPricePriceNewSubscriptionPercentCompositePriceConversionRateConfig] + """The configuration for the rate of the price currency to the invoicing currency.""" - Number of usage units that this discount is for + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" -class PriceOverrideOverrideUnitWithPercentPrice(TypedDict, total=False): - id: Required[str] + external_price_id: Optional[str] + """An alias for the price.""" - model_type: Required[Literal["unit_with_percent"]] + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - unit_with_percent_config: Required[Dict[str, object]] + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - discount: Optional[PriceOverrideOverrideUnitWithPercentPriceDiscount] - """The subscription's override discount for the plan.""" + invoicing_cycle_configuration: Optional[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + If unspecified, a single invoice is produced per billing cycle. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" - - -PriceOverride = Union[ - PriceOverrideOverrideUnitPrice, - PriceOverrideOverridePackagePrice, - PriceOverrideOverrideMatrixPrice, - PriceOverrideOverrideTieredPrice, - PriceOverrideOverrideTieredBpsPrice, - PriceOverrideOverrideBpsPrice, - PriceOverrideOverrideBulkBpsPrice, - PriceOverrideOverrideBulkPrice, - PriceOverrideOverrideThresholdTotalAmountPrice, - PriceOverrideOverrideTieredPackagePrice, - PriceOverrideOverrideTieredWithMinimumPrice, - PriceOverrideOverridePackageWithAllocationPrice, - PriceOverrideOverrideUnitWithPercentPrice, + 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 AddPricePriceNewSubscriptionEventOutputPriceEventOutputConfig(TypedDict, total=False): + """Configuration for event_output pricing""" + + unit_rating_key: Required[str] + """The key in the event data to extract the unit rate from.""" + + default_unit_rate: Optional[str] + """ + If provided, this amount will be used as the unit rate when an event does not + have a value for the `unit_rating_key`. If not provided, events missing a unit + rate will be ignored. + """ + + grouping_key: Optional[str] + """An optional key in the event data to group by (e.g., event ID). + + All events will also be grouped by their unit rate. + """ + + +AddPricePriceNewSubscriptionEventOutputPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig ] + + +class AddPricePriceNewSubscriptionEventOutputPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + event_output_config: Required[AddPricePriceNewSubscriptionEventOutputPriceEventOutputConfig] + """Configuration for event_output pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["event_output"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[AddPricePriceNewSubscriptionEventOutputPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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[ + NewSubscriptionUnitPriceParam, + NewSubscriptionTieredPriceParam, + NewSubscriptionBulkPriceParam, + AddPricePriceNewSubscriptionBulkWithFiltersPrice, + NewSubscriptionPackagePriceParam, + NewSubscriptionMatrixPriceParam, + NewSubscriptionThresholdTotalAmountPriceParam, + NewSubscriptionTieredPackagePriceParam, + NewSubscriptionTieredWithMinimumPriceParam, + NewSubscriptionGroupedTieredPriceParam, + NewSubscriptionTieredPackageWithMinimumPriceParam, + NewSubscriptionPackageWithAllocationPriceParam, + NewSubscriptionUnitWithPercentPriceParam, + NewSubscriptionMatrixWithAllocationPriceParam, + AddPricePriceNewSubscriptionMatrixWithThresholdDiscountsPrice, + AddPricePriceNewSubscriptionTieredWithProrationPrice, + NewSubscriptionUnitWithProrationPriceParam, + NewSubscriptionGroupedAllocationPriceParam, + NewSubscriptionBulkWithProrationPriceParam, + NewSubscriptionGroupedWithProratedMinimumPriceParam, + NewSubscriptionGroupedWithMeteredMinimumPriceParam, + AddPricePriceNewSubscriptionGroupedWithMinMaxThresholdsPrice, + NewSubscriptionMatrixWithDisplayNamePriceParam, + NewSubscriptionGroupedTieredPackagePriceParam, + NewSubscriptionMaxGroupTieredPackagePriceParam, + NewSubscriptionScalableMatrixWithUnitPricingPriceParam, + NewSubscriptionScalableMatrixWithTieredPricingPriceParam, + NewSubscriptionCumulativeGroupedBulkPriceParam, + AddPricePriceNewSubscriptionCumulativeGroupedAllocationPrice, + AddPricePriceNewSubscriptionDailyCreditAllowancePrice, + AddPricePriceNewSubscriptionMeteredAllowancePrice, + NewSubscriptionMinimumCompositePriceParam, + AddPricePriceNewSubscriptionPercentCompositePrice, + AddPricePriceNewSubscriptionEventOutputPrice, +] + + +class AddPrice(TypedDict, total=False): + allocation_price: Optional[NewAllocationPrice] + """The definition of a new allocation price to create and add to the subscription.""" + + discounts: Optional[Iterable[DiscountOverrideParam]] + """[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. + """ + + metric_parameter_overrides: Optional[Dict[str, object]] + """Override values for parameterized billable metric variables. + + Keys are parameter names, values are the override values. + """ + + 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] + """New subscription price request body params.""" + + 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 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 ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountTier(TypedDict, total=False): + lower_bound: Required[float] + """Exclusive lower bound of cumulative spend for this tier.""" + + percentage: Required[float] + """The percentage (0-1) discounted from spend in this tier.""" + + upper_bound: Optional[float] + """Inclusive upper bound of cumulative spend; null for the final open-ended tier.""" + + +class ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountFilter(TypedDict, total=False): + field: Required[Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]] + """The property of the price to filter on.""" + + operator: Required[Literal["includes", "excludes"]] + """Should prices that match the filter be included or excluded.""" + + values: Required[SequenceNotStr[str]] + """The IDs or values that match this filter.""" + + +class ReplaceAdjustmentAdjustmentNewTieredPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["tiered_percentage_discount"]] + + tiers: Required[Iterable[ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountTier]] + + applies_to_all: Optional[Literal[True]] + """If set, the adjustment will apply to every price on the subscription.""" + + applies_to_item_ids: Optional[SequenceNotStr[str]] + """The set of item IDs to which this adjustment applies.""" + + applies_to_price_ids: Optional[SequenceNotStr[str]] + """The set of price IDs to which this adjustment applies.""" + + currency: Optional[str] + """If set, only prices in the specified currency will have the adjustment applied.""" + + filters: Optional[Iterable[ReplaceAdjustmentAdjustmentNewTieredPercentageDiscountFilter]] + """A list of filters that determine which prices this adjustment will apply to.""" + + 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. + """ + + price_type: Optional[Literal["usage", "fixed_in_advance", "fixed_in_arrears", "fixed", "in_arrears"]] + """If set, only prices of the specified type will have the adjustment applied.""" + + +ReplaceAdjustmentAdjustment: TypeAlias = Union[ + NewPercentageDiscount, + NewUsageDiscount, + NewAmountDiscount, + NewMinimum, + NewMaximum, + ReplaceAdjustmentAdjustmentNewTieredPercentageDiscount, +] + + +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 ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigFilter(TypedDict, total=False): + """Configuration for a single property filter""" + + property_key: Required[str] + """Event property key to filter on""" + + property_value: Required[str] + """Event property value to match""" + + +class ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigTier(TypedDict, total=False): + """Configuration for a single bulk pricing tier""" + + unit_amount: Required[str] + """Amount per unit""" + + tier_lower_bound: Optional[str] + """The lower bound for this tier""" + + +class ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfig(TypedDict, total=False): + """Configuration for bulk_with_filters pricing""" + + filters: Required[Iterable[ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigFilter]] + """Property filters to apply (all must match)""" + + tiers: Required[Iterable[ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +ReplacePricePriceNewSubscriptionBulkWithFiltersPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionBulkWithFiltersPrice(TypedDict, total=False): + bulk_with_filters_config: Required[ReplacePricePriceNewSubscriptionBulkWithFiltersPriceBulkWithFiltersConfig] + """Configuration for bulk_with_filters pricing""" + + 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 price will be associated with.""" + + model_type: Required[Literal["bulk_with_filters"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewSubscriptionBulkWithFiltersPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue( + TypedDict, total=False +): + first_dimension_value: Required[str] + + unit_amount: Required[str] + + second_dimension_value: Optional[str] + + +class ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup( + TypedDict, total=False +): + above_threshold_discount_percentage: Required[str] + """Discount rate applied to spend above the threshold.""" + + below_threshold_discount_percentage: Required[str] + """Discount rate applied to spend at or below the threshold. + + Set to 0 for no baseline discount. + """ + + cell_coordinates: Required[str] + """Semicolon-separated list of matrix cell coordinates targeted by this group. + + Each coordinate is `first,second` when the matrix has two dimensions, or just + `first` for a single-dimension matrix. Example: `blue,circle;green,triangle`. + """ + + threshold_amount: Required[str] + + description: Optional[str] + + +class ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig( + TypedDict, total=False +): + """Configuration for matrix_with_threshold_discounts pricing""" + + default_unit_amount: Required[str] + """Unit price used for usage that does not match any defined matrix cell.""" + + first_dimension: Required[str] + """First matrix dimension key.""" + + matrix_values: Required[ + Iterable[ + ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigMatrixValue + ] + ] + """Per-cell unit prices.""" + + second_dimension: Optional[str] + """Optional second matrix dimension key.""" + + threshold_discount_groups: Iterable[ + ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfigThresholdDiscountGroup + ] + + +ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPrice(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 price will be associated with.""" + + matrix_with_threshold_discounts_config: Required[ + ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceMatrixWithThresholdDiscountsConfig + ] + """Configuration for matrix_with_threshold_discounts pricing""" + + model_type: Required[Literal["matrix_with_threshold_discounts"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ + ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPriceConversionRateConfig + ] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfigTier(TypedDict, total=False): + """Configuration for a single tiered with proration tier""" + + tier_lower_bound: Required[str] + """Inclusive tier starting value""" + + unit_amount: Required[str] + """Amount per unit""" + + +class ReplacePricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfig(TypedDict, total=False): + """Configuration for tiered_with_proration pricing""" + + tiers: Required[Iterable[ReplacePricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfigTier]] + """ + Tiers for rating based on total usage quantities into the specified tier with + proration + """ + + +ReplacePricePriceNewSubscriptionTieredWithProrationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionTieredWithProrationPrice(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 price will be associated with.""" + + model_type: Required[Literal["tiered_with_proration"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + tiered_with_proration_config: Required[ + ReplacePricePriceNewSubscriptionTieredWithProrationPriceTieredWithProrationConfig + ] + """Configuration for tiered_with_proration pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewSubscriptionTieredWithProrationPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig( + TypedDict, total=False +): + """Configuration for grouped_with_min_max_thresholds pricing""" + + grouping_key: Required[str] + """The event property used to group before applying thresholds""" + + maximum_charge: Required[str] + """The maximum amount to charge each group""" + + minimum_charge: Required[str] + """The minimum amount to charge each group, regardless of usage""" + + per_unit_rate: Required[str] + """The base price charged per group""" + + +ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_with_min_max_thresholds_config: Required[ + ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceGroupedWithMinMaxThresholdsConfig + ] + """Configuration for grouped_with_min_max_thresholds pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["grouped_with_min_max_thresholds"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ + ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPriceConversionRateConfig + ] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig( + TypedDict, total=False +): + """Configuration for cumulative_grouped_allocation pricing""" + + cumulative_allocation: Required[str] + """The overall allocation across all groups""" + + group_allocation: Required[str] + """The allocation per individual group""" + + grouping_key: Required[str] + """The event property used to group usage before applying allocations""" + + unit_amount: Required[str] + """The amount to charge for each unit outside of the allocation""" + + +ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + cumulative_grouped_allocation_config: Required[ + ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPriceCumulativeGroupedAllocationConfig + ] + """Configuration for cumulative_grouped_allocation pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["cumulative_grouped_allocation"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ + ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPriceConversionRateConfig + ] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue( + TypedDict, total=False +): + """Per-dimension credit price for the daily credit allowance model.""" + + dimension_values: Required[SequenceNotStr[Optional[str]]] + """One or two matrix keys to filter usage to this value by. + + For example, ["model"] could be used to apply a different credit rate to each AI + model. + """ + + unit_amount: Required[str] + """Credits charged per unit of usage matching the specified dimension_values""" + + +class ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfig(TypedDict, total=False): + """Configuration for daily_credit_allowance pricing""" + + daily_allowance: Required[str] + """Credits granted per day. Lose-it-or-use-it; does not roll over.""" + + default_unit_amount: Required[str] + """ + Default per-unit credit rate for any usage not bucketed into a specified + matrix_value + """ + + dimensions: Required[SequenceNotStr[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" + + event_day_property: Required[str] + """Event property whose value identifies the day bucket the event belongs to (e.g. + + 'event_day' set to an ISO date string in the customer's timezone). The allowance + resets per distinct value of this property. + """ + + matrix_values: Required[ + Iterable[ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfigMatrixValue] + ] + """Per-dimension credit rates""" + + +ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionDailyCreditAllowancePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + daily_credit_allowance_config: Required[ + ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceDailyCreditAllowanceConfig + ] + """Configuration for daily_credit_allowance pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["daily_credit_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewSubscriptionDailyCreditAllowancePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionMeteredAllowancePriceMeteredAllowanceConfig(TypedDict, total=False): + """Configuration for metered_allowance pricing""" + + allowance_grouping_value: Required[str] + """ + The grouping_key value whose summed quantity represents the allowance for this + period (e.g. 'storage_snapshot' emitting 3 × avg storage). Capped at consumption + — credit can never exceed actual usage. + """ + + consumption_grouping_value: Required[str] + """The grouping_key value whose summed quantity represents consumption (e.g. + + 'download'). Charged at unit_amount. + """ + + grouping_key: Required[str] + """ + Event property used to partition the metric into consumption and allowance + quantities (e.g. 'event_name'). The metric is queried with this key and the two + values below select which partition is which. + """ + + unit_amount: Required[str] + """Per-unit price applied to gross consumption and to the allowance credit.""" + + allowance_display_name: str + """Sub-line label for the credit row (e.g. 'Up to 3x free egress').""" + + consumption_display_name: str + """Sub-line label for the gross consumption row (e.g. 'bytes gotten').""" + + +ReplacePricePriceNewSubscriptionMeteredAllowancePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionMeteredAllowancePrice(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 price will be associated with.""" + + metered_allowance_config: Required[ReplacePricePriceNewSubscriptionMeteredAllowancePriceMeteredAllowanceConfig] + """Configuration for metered_allowance pricing""" + + model_type: Required[Literal["metered_allowance"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewSubscriptionMeteredAllowancePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionPercentCompositePricePercentConfig(TypedDict, total=False): + """Configuration for percent pricing""" + + percent: Required[float] + """Fraction of the component subtotals to charge (0 < percent <= 1).""" + + maximum_amount: Optional[str] + """Maximum amount to charge. If unset, the fee has no upper bound.""" + + minimum_amount: Optional[str] + """Minimum amount to charge. If unset, the fee is bounded below by 0.""" + + prorated: bool + """If true, the minimum_amount is prorated based on the service period. + + The maximum_amount is an absolute cap (never prorated), and the percent applied + to upstream subtotals is never prorated either. + """ + + +ReplacePricePriceNewSubscriptionPercentCompositePriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionPercentCompositePrice(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 price will be associated with.""" + + model_type: Required[Literal["percent"]] + """The pricing model type""" + + name: Required[str] + """The name of the price.""" + + percent_config: Required[ReplacePricePriceNewSubscriptionPercentCompositePricePercentConfig] + """Configuration for percent pricing""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewSubscriptionPercentCompositePriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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 ReplacePricePriceNewSubscriptionEventOutputPriceEventOutputConfig(TypedDict, total=False): + """Configuration for event_output pricing""" + + unit_rating_key: Required[str] + """The key in the event data to extract the unit rate from.""" + + default_unit_rate: Optional[str] + """ + If provided, this amount will be used as the unit rate when an event does not + have a value for the `unit_rating_key`. If not provided, events missing a unit + rate will be ignored. + """ + + grouping_key: Optional[str] + """An optional key in the event data to group by (e.g., event ID). + + All events will also be grouped by their unit rate. + """ + + +ReplacePricePriceNewSubscriptionEventOutputPriceConversionRateConfig: TypeAlias = Union[ + UnitConversionRateConfig, TieredConversionRateConfig +] + + +class ReplacePricePriceNewSubscriptionEventOutputPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + event_output_config: Required[ReplacePricePriceNewSubscriptionEventOutputPriceEventOutputConfig] + """Configuration for event_output pricing""" + + item_id: Required[str] + """The id of the item the price will be associated with.""" + + model_type: Required[Literal["event_output"]] + """The pricing model type""" + + 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[NewBillingCycleConfiguration] + """ + 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.""" + + conversion_rate_config: Optional[ReplacePricePriceNewSubscriptionEventOutputPriceConversionRateConfig] + """The configuration for the 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. + """ + + dimensional_price_configuration: Optional[NewDimensionalPriceConfiguration] + """For dimensional price: specifies a price group and dimension values""" + + 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[NewBillingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + license_type_id: Optional[str] + """The ID of the license type to associate with this price.""" + + 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[ + NewSubscriptionUnitPriceParam, + NewSubscriptionTieredPriceParam, + NewSubscriptionBulkPriceParam, + ReplacePricePriceNewSubscriptionBulkWithFiltersPrice, + NewSubscriptionPackagePriceParam, + NewSubscriptionMatrixPriceParam, + NewSubscriptionThresholdTotalAmountPriceParam, + NewSubscriptionTieredPackagePriceParam, + NewSubscriptionTieredWithMinimumPriceParam, + NewSubscriptionGroupedTieredPriceParam, + NewSubscriptionTieredPackageWithMinimumPriceParam, + NewSubscriptionPackageWithAllocationPriceParam, + NewSubscriptionUnitWithPercentPriceParam, + NewSubscriptionMatrixWithAllocationPriceParam, + ReplacePricePriceNewSubscriptionMatrixWithThresholdDiscountsPrice, + ReplacePricePriceNewSubscriptionTieredWithProrationPrice, + NewSubscriptionUnitWithProrationPriceParam, + NewSubscriptionGroupedAllocationPriceParam, + NewSubscriptionBulkWithProrationPriceParam, + NewSubscriptionGroupedWithProratedMinimumPriceParam, + NewSubscriptionGroupedWithMeteredMinimumPriceParam, + ReplacePricePriceNewSubscriptionGroupedWithMinMaxThresholdsPrice, + NewSubscriptionMatrixWithDisplayNamePriceParam, + NewSubscriptionGroupedTieredPackagePriceParam, + NewSubscriptionMaxGroupTieredPackagePriceParam, + NewSubscriptionScalableMatrixWithUnitPricingPriceParam, + NewSubscriptionScalableMatrixWithTieredPricingPriceParam, + NewSubscriptionCumulativeGroupedBulkPriceParam, + ReplacePricePriceNewSubscriptionCumulativeGroupedAllocationPrice, + ReplacePricePriceNewSubscriptionDailyCreditAllowancePrice, + ReplacePricePriceNewSubscriptionMeteredAllowancePrice, + NewSubscriptionMinimumCompositePriceParam, + ReplacePricePriceNewSubscriptionPercentCompositePrice, + ReplacePricePriceNewSubscriptionEventOutputPrice, +] + + +class ReplacePrice(TypedDict, total=False): + replaces_price_id: Required[str] + """The id of the price on the plan to replace in the subscription.""" + + allocation_price: Optional[NewAllocationPrice] + """The definition of a new allocation price to create and add to the subscription.""" + + discounts: Optional[Iterable[DiscountOverrideParam]] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's discounts for the replacement price. + """ + + external_price_id: Optional[str] + """The external price id of the price to add to the subscription.""" + + fixed_price_quantity: Optional[float] + """The new quantity of the price, if the price is a fixed price.""" + + maximum_amount: Optional[str] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's maximum amount for the replacement price. + """ + + metric_parameter_overrides: Optional[Dict[str, object]] + """Override values for parameterized billable metric variables. + + Keys are parameter names, values are the override values. + """ + + minimum_amount: Optional[str] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's minimum amount for the replacement price. + """ + + price: Optional[ReplacePricePrice] + """New subscription price request body params.""" + + price_id: Optional[str] + """The id of the price to add to the subscription.""" diff --git a/src/orb/types/subscription_trigger_phase_params.py b/src/orb/types/subscription_trigger_phase_params.py index 504862ad..59367f7a 100644 --- a/src/orb/types/subscription_trigger_phase_params.py +++ b/src/orb/types/subscription_trigger_phase_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union +from typing import Union, Optional from datetime import date from typing_extensions import Annotated, TypedDict @@ -12,6 +12,13 @@ class SubscriptionTriggerPhaseParams(TypedDict, total=False): + allow_invoice_credit_or_void: Optional[bool] + """ + If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + """ + effective_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] """The date on which the phase change should take effect. diff --git a/src/orb/types/subscription_update_fixed_fee_quantity_params.py b/src/orb/types/subscription_update_fixed_fee_quantity_params.py index 2fa701f1..f3b3570f 100644 --- a/src/orb/types/subscription_update_fixed_fee_quantity_params.py +++ b/src/orb/types/subscription_update_fixed_fee_quantity_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union +from typing import Union, Optional from datetime import date from typing_extensions import Literal, Required, Annotated, TypedDict @@ -17,17 +17,24 @@ class SubscriptionUpdateFixedFeeQuantityParams(TypedDict, total=False): quantity: Required[float] + allow_invoice_credit_or_void: Optional[bool] + """ + If false, this request will fail if it would void an issued invoice or create a + credit note. Consider using this as a safety mechanism if you do not expect + existing invoices to be changed. + """ + change_option: Literal["immediate", "upcoming_invoice", "effective_date"] """Determines when the change takes effect. Note that if `effective_date` is specified, this defaults to `effective_date`. Otherwise, this defaults to `immediate` unless it's explicitly set to - `upcoming_invoice. + `upcoming_invoice`. """ effective_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] """ The date that the quantity change should take effect, localized to the - customer's timezone. Ifthis parameter is not passed in, the quantity change is + customer's timezone. If this parameter is not passed in, the quantity change is effective according to `change_option`. """ diff --git a/src/orb/types/subscription_update_params.py b/src/orb/types/subscription_update_params.py new file mode 100644 index 00000000..d9899829 --- /dev/null +++ b/src/orb/types/subscription_update_params.py @@ -0,0 +1,54 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import TypedDict + +__all__ = ["SubscriptionUpdateParams"] + + +class SubscriptionUpdateParams(TypedDict, total=False): + auto_collection: Optional[bool] + """ + 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. + """ + + auto_issuance: Optional[bool] + """Used to determine if invoices for this subscription will be automatically + issued. + + If true, invoices will be automatically issued. If false, invoices will require + manual approval. If `null` is specified, this defaults to the behavior + configured for this customer. + """ + + default_invoice_memo: Optional[str] + """Determines the default memo on this subscription's invoices. + + Note that if this is not provided, it is determined by the plan configuration. + """ + + invoicing_threshold: Optional[str] + """ + When this subscription's accrued usage reaches this threshold, an invoice will + be issued for the subscription. If not specified, invoices will only be issued + at the end of the billing period. + """ + + 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`. + """ + + net_terms: Optional[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. + """ 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_usage.py b/src/orb/types/subscription_usage.py index 8dc7836e..4a5c4f2e 100644 --- a/src/orb/types/subscription_usage.py +++ b/src/orb/types/subscription_usage.py @@ -2,9 +2,10 @@ from typing import List, Union, Optional from datetime import datetime -from typing_extensions import Literal +from typing_extensions import Literal, TypeAlias from .._models import BaseModel +from .shared.pagination_metadata import PaginationMetadata __all__ = [ "SubscriptionUsage", @@ -17,7 +18,6 @@ "GroupedSubscriptionUsageDataBillableMetric", "GroupedSubscriptionUsageDataMetricGroup", "GroupedSubscriptionUsageDataUsage", - "GroupedSubscriptionUsagePaginationMetadata", ] @@ -77,16 +77,10 @@ class GroupedSubscriptionUsageData(BaseModel): view_mode: Literal["periodic", "cumulative"] -class GroupedSubscriptionUsagePaginationMetadata(BaseModel): - has_more: bool - - next_cursor: Optional[str] = None - - class GroupedSubscriptionUsage(BaseModel): data: List[GroupedSubscriptionUsageData] - pagination_metadata: Optional[GroupedSubscriptionUsagePaginationMetadata] = None + pagination_metadata: Optional[PaginationMetadata] = None -SubscriptionUsage = Union[UngroupedSubscriptionUsage, GroupedSubscriptionUsage] +SubscriptionUsage: TypeAlias = Union[UngroupedSubscriptionUsage, GroupedSubscriptionUsage] diff --git a/src/orb/types/subscriptions.py b/src/orb/types/subscriptions.py index 9844a09b..c80fef11 100644 --- a/src/orb/types/subscriptions.py +++ b/src/orb/types/subscriptions.py @@ -1,17 +1,12 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional +from typing import List from .._models import BaseModel from .subscription import Subscription +from .shared.pagination_metadata import PaginationMetadata -__all__ = ["Subscriptions", "PaginationMetadata"] - - -class PaginationMetadata(BaseModel): - has_more: bool - - next_cursor: Optional[str] = None +__all__ = ["Subscriptions"] class Subscriptions(BaseModel): diff --git a/src/orb/types/threshold.py b/src/orb/types/threshold.py new file mode 100644 index 00000000..6b889abb --- /dev/null +++ b/src/orb/types/threshold.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["Threshold"] + + +class Threshold(BaseModel): + """ + Thresholds are used to define the conditions under which an alert will be triggered. + """ + + value: float + """The value at which an alert will fire. + + For credit balance alerts, the alert will fire at or below this value. For usage + and cost alerts, the alert will fire at or above this value. + """ diff --git a/src/orb/types/threshold_param.py b/src/orb/types/threshold_param.py new file mode 100644 index 00000000..a175e35c --- /dev/null +++ b/src/orb/types/threshold_param.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ThresholdParam"] + + +class ThresholdParam(TypedDict, total=False): + """ + Thresholds are used to define the conditions under which an alert will be triggered. + """ + + value: Required[float] + """The value at which an alert will fire. + + For credit balance alerts, the alert will fire at or below this value. For usage + and cost alerts, the alert will fire at or above this value. + """ diff --git a/tests/api_resources/beta/test_external_plan_id.py b/tests/api_resources/beta/test_external_plan_id.py new file mode 100644 index 00000000..15b702e7 --- /dev/null +++ b/tests/api_resources/beta/test_external_plan_id.py @@ -0,0 +1,850 @@ +# 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.types import Plan, PlanVersion +from tests.utils import assert_matches_type + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestExternalPlanID: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create_plan_version(self, client: Orb) -> None: + external_plan_id = client.beta.external_plan_id.create_plan_version( + external_plan_id="external_plan_id", + version=0, + ) + assert_matches_type(PlanVersion, external_plan_id, path=["response"]) + + @parametrize + def test_method_create_plan_version_with_all_params(self, client: Orb) -> None: + external_plan_id = client.beta.external_plan_id.create_plan_version( + external_plan_id="external_plan_id", + version=0, + add_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "plan_phase_order": 0, + } + ], + add_prices=[ + { + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "license_allocation_price": { + "cadence": "annual", + "item_id": "item_id", + "license_allocations": [ + { + "amount": "amount", + "currency": "currency", + "write_off_overage": True, + } + ], + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "plan_phase_order": 0, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + } + ], + remove_adjustments=[ + { + "adjustment_id": "adjustment_id", + "plan_phase_order": 0, + } + ], + remove_prices=[ + { + "price_id": "price_id", + "plan_phase_order": 0, + } + ], + replace_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "replaces_adjustment_id": "replaces_adjustment_id", + "plan_phase_order": 0, + } + ], + replace_prices=[ + { + "replaces_price_id": "replaces_price_id", + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "license_allocation_price": { + "cadence": "annual", + "item_id": "item_id", + "license_allocations": [ + { + "amount": "amount", + "currency": "currency", + "write_off_overage": True, + } + ], + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "plan_phase_order": 0, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + } + ], + set_as_default=True, + ) + assert_matches_type(PlanVersion, external_plan_id, path=["response"]) + + @parametrize + def test_raw_response_create_plan_version(self, client: Orb) -> None: + response = client.beta.external_plan_id.with_raw_response.create_plan_version( + external_plan_id="external_plan_id", + version=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_plan_id = response.parse() + assert_matches_type(PlanVersion, external_plan_id, path=["response"]) + + @parametrize + def test_streaming_response_create_plan_version(self, client: Orb) -> None: + with client.beta.external_plan_id.with_streaming_response.create_plan_version( + external_plan_id="external_plan_id", + version=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_plan_id = response.parse() + assert_matches_type(PlanVersion, external_plan_id, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create_plan_version(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_plan_id` but received ''"): + client.beta.external_plan_id.with_raw_response.create_plan_version( + external_plan_id="", + version=0, + ) + + @parametrize + def test_method_fetch_plan_version(self, client: Orb) -> None: + external_plan_id = client.beta.external_plan_id.fetch_plan_version( + version="version", + external_plan_id="external_plan_id", + ) + assert_matches_type(PlanVersion, external_plan_id, path=["response"]) + + @parametrize + def test_raw_response_fetch_plan_version(self, client: Orb) -> None: + response = client.beta.external_plan_id.with_raw_response.fetch_plan_version( + version="version", + external_plan_id="external_plan_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_plan_id = response.parse() + assert_matches_type(PlanVersion, external_plan_id, path=["response"]) + + @parametrize + def test_streaming_response_fetch_plan_version(self, client: Orb) -> None: + with client.beta.external_plan_id.with_streaming_response.fetch_plan_version( + version="version", + external_plan_id="external_plan_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_plan_id = response.parse() + assert_matches_type(PlanVersion, external_plan_id, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_fetch_plan_version(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_plan_id` but received ''"): + client.beta.external_plan_id.with_raw_response.fetch_plan_version( + version="version", + external_plan_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `version` but received ''"): + client.beta.external_plan_id.with_raw_response.fetch_plan_version( + version="", + external_plan_id="external_plan_id", + ) + + @parametrize + def test_method_set_default_plan_version(self, client: Orb) -> None: + external_plan_id = client.beta.external_plan_id.set_default_plan_version( + external_plan_id="external_plan_id", + version=0, + ) + assert_matches_type(Plan, external_plan_id, path=["response"]) + + @parametrize + def test_raw_response_set_default_plan_version(self, client: Orb) -> None: + response = client.beta.external_plan_id.with_raw_response.set_default_plan_version( + external_plan_id="external_plan_id", + version=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_plan_id = response.parse() + assert_matches_type(Plan, external_plan_id, path=["response"]) + + @parametrize + def test_streaming_response_set_default_plan_version(self, client: Orb) -> None: + with client.beta.external_plan_id.with_streaming_response.set_default_plan_version( + external_plan_id="external_plan_id", + version=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_plan_id = response.parse() + assert_matches_type(Plan, external_plan_id, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_set_default_plan_version(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_plan_id` but received ''"): + client.beta.external_plan_id.with_raw_response.set_default_plan_version( + external_plan_id="", + version=0, + ) + + +class TestAsyncExternalPlanID: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create_plan_version(self, async_client: AsyncOrb) -> None: + external_plan_id = await async_client.beta.external_plan_id.create_plan_version( + external_plan_id="external_plan_id", + version=0, + ) + assert_matches_type(PlanVersion, external_plan_id, path=["response"]) + + @parametrize + async def test_method_create_plan_version_with_all_params(self, async_client: AsyncOrb) -> None: + external_plan_id = await async_client.beta.external_plan_id.create_plan_version( + external_plan_id="external_plan_id", + version=0, + add_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "plan_phase_order": 0, + } + ], + add_prices=[ + { + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "license_allocation_price": { + "cadence": "annual", + "item_id": "item_id", + "license_allocations": [ + { + "amount": "amount", + "currency": "currency", + "write_off_overage": True, + } + ], + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "plan_phase_order": 0, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + } + ], + remove_adjustments=[ + { + "adjustment_id": "adjustment_id", + "plan_phase_order": 0, + } + ], + remove_prices=[ + { + "price_id": "price_id", + "plan_phase_order": 0, + } + ], + replace_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "replaces_adjustment_id": "replaces_adjustment_id", + "plan_phase_order": 0, + } + ], + replace_prices=[ + { + "replaces_price_id": "replaces_price_id", + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "license_allocation_price": { + "cadence": "annual", + "item_id": "item_id", + "license_allocations": [ + { + "amount": "amount", + "currency": "currency", + "write_off_overage": True, + } + ], + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "plan_phase_order": 0, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + } + ], + set_as_default=True, + ) + assert_matches_type(PlanVersion, external_plan_id, path=["response"]) + + @parametrize + async def test_raw_response_create_plan_version(self, async_client: AsyncOrb) -> None: + response = await async_client.beta.external_plan_id.with_raw_response.create_plan_version( + external_plan_id="external_plan_id", + version=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_plan_id = response.parse() + assert_matches_type(PlanVersion, external_plan_id, path=["response"]) + + @parametrize + async def test_streaming_response_create_plan_version(self, async_client: AsyncOrb) -> None: + async with async_client.beta.external_plan_id.with_streaming_response.create_plan_version( + external_plan_id="external_plan_id", + version=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_plan_id = await response.parse() + assert_matches_type(PlanVersion, external_plan_id, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create_plan_version(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_plan_id` but received ''"): + await async_client.beta.external_plan_id.with_raw_response.create_plan_version( + external_plan_id="", + version=0, + ) + + @parametrize + async def test_method_fetch_plan_version(self, async_client: AsyncOrb) -> None: + external_plan_id = await async_client.beta.external_plan_id.fetch_plan_version( + version="version", + external_plan_id="external_plan_id", + ) + assert_matches_type(PlanVersion, external_plan_id, path=["response"]) + + @parametrize + async def test_raw_response_fetch_plan_version(self, async_client: AsyncOrb) -> None: + response = await async_client.beta.external_plan_id.with_raw_response.fetch_plan_version( + version="version", + external_plan_id="external_plan_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_plan_id = response.parse() + assert_matches_type(PlanVersion, external_plan_id, path=["response"]) + + @parametrize + async def test_streaming_response_fetch_plan_version(self, async_client: AsyncOrb) -> None: + async with async_client.beta.external_plan_id.with_streaming_response.fetch_plan_version( + version="version", + external_plan_id="external_plan_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_plan_id = await response.parse() + assert_matches_type(PlanVersion, external_plan_id, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_fetch_plan_version(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_plan_id` but received ''"): + await async_client.beta.external_plan_id.with_raw_response.fetch_plan_version( + version="version", + external_plan_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `version` but received ''"): + await async_client.beta.external_plan_id.with_raw_response.fetch_plan_version( + version="", + external_plan_id="external_plan_id", + ) + + @parametrize + async def test_method_set_default_plan_version(self, async_client: AsyncOrb) -> None: + external_plan_id = await async_client.beta.external_plan_id.set_default_plan_version( + external_plan_id="external_plan_id", + version=0, + ) + assert_matches_type(Plan, external_plan_id, path=["response"]) + + @parametrize + async def test_raw_response_set_default_plan_version(self, async_client: AsyncOrb) -> None: + response = await async_client.beta.external_plan_id.with_raw_response.set_default_plan_version( + external_plan_id="external_plan_id", + version=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_plan_id = response.parse() + assert_matches_type(Plan, external_plan_id, path=["response"]) + + @parametrize + async def test_streaming_response_set_default_plan_version(self, async_client: AsyncOrb) -> None: + async with async_client.beta.external_plan_id.with_streaming_response.set_default_plan_version( + external_plan_id="external_plan_id", + version=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_plan_id = await response.parse() + assert_matches_type(Plan, external_plan_id, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_set_default_plan_version(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_plan_id` but received ''"): + await async_client.beta.external_plan_id.with_raw_response.set_default_plan_version( + external_plan_id="", + version=0, + ) diff --git a/tests/api_resources/beta/test_price.py b/tests/api_resources/beta/test_price.py deleted file mode 100644 index bb1def05..00000000 --- a/tests/api_resources/beta/test_price.py +++ /dev/null @@ -1,141 +0,0 @@ -# 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.beta import PriceEvaluateResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestPrice: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_evaluate(self, client: Orb) -> None: - price = client.beta.price.evaluate( - "string", - timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), - timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(PriceEvaluateResponse, price, path=["response"]) - - @parametrize - def test_method_evaluate_with_all_params(self, client: Orb) -> None: - price = client.beta.price.evaluate( - "string", - timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), - timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), - customer_id="string", - external_customer_id="string", - filter="my_numeric_property > 100 AND my_other_property = 'bar'", - grouping_keys=["case when my_event_type = 'foo' then true else false end"], - ) - assert_matches_type(PriceEvaluateResponse, price, path=["response"]) - - @parametrize - def test_raw_response_evaluate(self, client: Orb) -> None: - response = client.beta.price.with_raw_response.evaluate( - "string", - timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), - 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" - price = response.parse() - assert_matches_type(PriceEvaluateResponse, price, path=["response"]) - - @parametrize - def test_streaming_response_evaluate(self, client: Orb) -> None: - with client.beta.price.with_streaming_response.evaluate( - "string", - timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), - 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" - - price = response.parse() - assert_matches_type(PriceEvaluateResponse, price, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_evaluate(self, client: Orb) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `price_id` but received ''"): - client.beta.price.with_raw_response.evaluate( - "", - timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), - timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - - -class TestAsyncPrice: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - async def test_method_evaluate(self, async_client: AsyncOrb) -> None: - price = await async_client.beta.price.evaluate( - "string", - timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), - timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(PriceEvaluateResponse, price, path=["response"]) - - @parametrize - async def test_method_evaluate_with_all_params(self, async_client: AsyncOrb) -> None: - price = await async_client.beta.price.evaluate( - "string", - timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), - timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), - customer_id="string", - external_customer_id="string", - filter="my_numeric_property > 100 AND my_other_property = 'bar'", - grouping_keys=["case when my_event_type = 'foo' then true else false end"], - ) - assert_matches_type(PriceEvaluateResponse, price, path=["response"]) - - @parametrize - async def test_raw_response_evaluate(self, async_client: AsyncOrb) -> None: - response = await async_client.beta.price.with_raw_response.evaluate( - "string", - timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), - 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" - price = response.parse() - assert_matches_type(PriceEvaluateResponse, price, path=["response"]) - - @parametrize - async def test_streaming_response_evaluate(self, async_client: AsyncOrb) -> None: - async with async_client.beta.price.with_streaming_response.evaluate( - "string", - timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), - 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" - - price = await response.parse() - assert_matches_type(PriceEvaluateResponse, price, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_evaluate(self, async_client: AsyncOrb) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `price_id` but received ''"): - await async_client.beta.price.with_raw_response.evaluate( - "", - timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), - timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), - ) diff --git a/tests/api_resources/coupons/test_subscriptions.py b/tests/api_resources/coupons/test_subscriptions.py index 4b57ab69..cbf1e1d2 100644 --- a/tests/api_resources/coupons/test_subscriptions.py +++ b/tests/api_resources/coupons/test_subscriptions.py @@ -21,23 +21,23 @@ class TestSubscriptions: @parametrize def test_method_list(self, client: Orb) -> None: subscription = client.coupons.subscriptions.list( - "string", + coupon_id="coupon_id", ) assert_matches_type(SyncPage[Subscription], subscription, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: Orb) -> None: subscription = client.coupons.subscriptions.list( - "string", - cursor="string", - limit=0, + coupon_id="coupon_id", + cursor="cursor", + limit=1, ) assert_matches_type(SyncPage[Subscription], subscription, path=["response"]) @parametrize def test_raw_response_list(self, client: Orb) -> None: response = client.coupons.subscriptions.with_raw_response.list( - "string", + coupon_id="coupon_id", ) assert response.is_closed is True @@ -48,7 +48,7 @@ def test_raw_response_list(self, client: Orb) -> None: @parametrize def test_streaming_response_list(self, client: Orb) -> None: with client.coupons.subscriptions.with_streaming_response.list( - "string", + coupon_id="coupon_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -62,33 +62,35 @@ def test_streaming_response_list(self, client: Orb) -> None: def test_path_params_list(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `coupon_id` but received ''"): client.coupons.subscriptions.with_raw_response.list( - "", + coupon_id="", ) class TestAsyncSubscriptions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncOrb) -> None: subscription = await async_client.coupons.subscriptions.list( - "string", + coupon_id="coupon_id", ) assert_matches_type(AsyncPage[Subscription], subscription, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: subscription = await async_client.coupons.subscriptions.list( - "string", - cursor="string", - limit=0, + coupon_id="coupon_id", + cursor="cursor", + limit=1, ) assert_matches_type(AsyncPage[Subscription], subscription, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOrb) -> None: response = await async_client.coupons.subscriptions.with_raw_response.list( - "string", + coupon_id="coupon_id", ) assert response.is_closed is True @@ -99,7 +101,7 @@ async def test_raw_response_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: async with async_client.coupons.subscriptions.with_streaming_response.list( - "string", + coupon_id="coupon_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -113,5 +115,5 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: async def test_path_params_list(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `coupon_id` but received ''"): await async_client.coupons.subscriptions.with_raw_response.list( - "", + coupon_id="", ) diff --git a/tests/api_resources/customers/credits/test_ledger.py b/tests/api_resources/customers/credits/test_ledger.py index b5d9bf38..d056bec6 100644 --- a/tests/api_resources/customers/credits/test_ledger.py +++ b/tests/api_resources/customers/credits/test_ledger.py @@ -27,31 +27,31 @@ class TestLedger: @parametrize def test_method_list(self, client: Orb) -> None: ledger = client.customers.credits.ledger.list( - "string", + customer_id="customer_id", ) assert_matches_type(SyncPage[LedgerListResponse], ledger, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: Orb) -> None: ledger = client.customers.credits.ledger.list( - "string", + customer_id="customer_id", created_at_gt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), - currency="string", - cursor="string", + currency="currency", + cursor="cursor", entry_status="committed", entry_type="increment", - limit=0, - minimum_amount="string", + limit=1, + minimum_amount="minimum_amount", ) assert_matches_type(SyncPage[LedgerListResponse], ledger, path=["response"]) @parametrize def test_raw_response_list(self, client: Orb) -> None: response = client.customers.credits.ledger.with_raw_response.list( - "string", + customer_id="customer_id", ) assert response.is_closed is True @@ -62,7 +62,7 @@ def test_raw_response_list(self, client: Orb) -> None: @parametrize def test_streaming_response_list(self, client: Orb) -> None: with client.customers.credits.ledger.with_streaming_response.list( - "string", + customer_id="customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -76,13 +76,13 @@ def test_streaming_response_list(self, client: Orb) -> None: def test_path_params_list(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): client.customers.credits.ledger.with_raw_response.list( - "", + customer_id="", ) @parametrize def test_method_create_entry_overload_1(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="increment", ) @@ -91,27 +91,39 @@ def test_method_create_entry_overload_1(self, client: Orb) -> None: @parametrize def test_method_create_entry_with_all_params_overload_1(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="increment", - currency="string", - description="string", + currency="currency", + description="description", effective_date=parse_datetime("2019-12-27T18:11:19.117Z"), expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), + filters=[ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], invoice_settings={ "auto_collection": True, + "custom_due_date": parse_date("2019-12-27"), + "invoice_date": parse_date("2019-12-27"), + "item_id": "item_id", + "mark_as_paid": True, + "memo": "memo", "net_terms": 0, - "memo": "string", + "require_successful_payment": True, }, metadata={"foo": "string"}, - per_unit_cost_basis="string", + per_unit_cost_basis="per_unit_cost_basis", ) assert_matches_type(LedgerCreateEntryResponse, ledger, path=["response"]) @parametrize def test_raw_response_create_entry_overload_1(self, client: Orb) -> None: response = client.customers.credits.ledger.with_raw_response.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="increment", ) @@ -124,7 +136,7 @@ def test_raw_response_create_entry_overload_1(self, client: Orb) -> None: @parametrize def test_streaming_response_create_entry_overload_1(self, client: Orb) -> None: with client.customers.credits.ledger.with_streaming_response.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="increment", ) as response: @@ -140,7 +152,7 @@ def test_streaming_response_create_entry_overload_1(self, client: Orb) -> None: def test_path_params_create_entry_overload_1(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): client.customers.credits.ledger.with_raw_response.create_entry( - "", + customer_id="", amount=0, entry_type="increment", ) @@ -148,7 +160,7 @@ def test_path_params_create_entry_overload_1(self, client: Orb) -> None: @parametrize def test_method_create_entry_overload_2(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="decrement", ) @@ -157,11 +169,11 @@ def test_method_create_entry_overload_2(self, client: Orb) -> None: @parametrize def test_method_create_entry_with_all_params_overload_2(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="decrement", - currency="string", - description="string", + currency="currency", + description="description", metadata={"foo": "string"}, ) assert_matches_type(LedgerCreateEntryResponse, ledger, path=["response"]) @@ -169,7 +181,7 @@ def test_method_create_entry_with_all_params_overload_2(self, client: Orb) -> No @parametrize def test_raw_response_create_entry_overload_2(self, client: Orb) -> None: response = client.customers.credits.ledger.with_raw_response.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="decrement", ) @@ -182,7 +194,7 @@ def test_raw_response_create_entry_overload_2(self, client: Orb) -> None: @parametrize def test_streaming_response_create_entry_overload_2(self, client: Orb) -> None: with client.customers.credits.ledger.with_streaming_response.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="decrement", ) as response: @@ -198,7 +210,7 @@ def test_streaming_response_create_entry_overload_2(self, client: Orb) -> None: def test_path_params_create_entry_overload_2(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): client.customers.credits.ledger.with_raw_response.create_entry( - "", + customer_id="", amount=0, entry_type="decrement", ) @@ -206,9 +218,8 @@ def test_path_params_create_entry_overload_2(self, client: Orb) -> None: @parametrize def test_method_create_entry_overload_3(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) assert_matches_type(LedgerCreateEntryResponse, ledger, path=["response"]) @@ -216,14 +227,14 @@ def test_method_create_entry_overload_3(self, client: Orb) -> None: @parametrize def test_method_create_entry_with_all_params_overload_3(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), amount=0, - block_id="string", - currency="string", - description="string", + block_id="block_id", + currency="currency", + description="description", + expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), metadata={"foo": "string"}, ) assert_matches_type(LedgerCreateEntryResponse, ledger, path=["response"]) @@ -231,9 +242,8 @@ def test_method_create_entry_with_all_params_overload_3(self, client: Orb) -> No @parametrize def test_raw_response_create_entry_overload_3(self, client: Orb) -> None: response = client.customers.credits.ledger.with_raw_response.create_entry( - "string", + customer_id="customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) @@ -245,9 +255,8 @@ def test_raw_response_create_entry_overload_3(self, client: Orb) -> None: @parametrize def test_streaming_response_create_entry_overload_3(self, client: Orb) -> None: with client.customers.credits.ledger.with_streaming_response.create_entry( - "string", + customer_id="customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) as response: assert not response.is_closed @@ -262,18 +271,17 @@ def test_streaming_response_create_entry_overload_3(self, client: Orb) -> None: def test_path_params_create_entry_overload_3(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): client.customers.credits.ledger.with_raw_response.create_entry( - "", + customer_id="", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) @parametrize def test_method_create_entry_overload_4(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) assert_matches_type(LedgerCreateEntryResponse, ledger, path=["response"]) @@ -281,12 +289,12 @@ def test_method_create_entry_overload_4(self, client: Orb) -> None: @parametrize def test_method_create_entry_with_all_params_overload_4(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", - currency="string", - description="string", + currency="currency", + description="description", metadata={"foo": "string"}, void_reason="refund", ) @@ -295,9 +303,9 @@ def test_method_create_entry_with_all_params_overload_4(self, client: Orb) -> No @parametrize def test_raw_response_create_entry_overload_4(self, client: Orb) -> None: response = client.customers.credits.ledger.with_raw_response.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) @@ -309,9 +317,9 @@ def test_raw_response_create_entry_overload_4(self, client: Orb) -> None: @parametrize def test_streaming_response_create_entry_overload_4(self, client: Orb) -> None: with client.customers.credits.ledger.with_streaming_response.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) as response: assert not response.is_closed @@ -326,18 +334,18 @@ def test_streaming_response_create_entry_overload_4(self, client: Orb) -> None: def test_path_params_create_entry_overload_4(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): client.customers.credits.ledger.with_raw_response.create_entry( - "", + customer_id="", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) @parametrize def test_method_create_entry_overload_5(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) assert_matches_type(LedgerCreateEntryResponse, ledger, path=["response"]) @@ -345,12 +353,12 @@ def test_method_create_entry_overload_5(self, client: Orb) -> None: @parametrize def test_method_create_entry_with_all_params_overload_5(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", - currency="string", - description="string", + currency="currency", + description="description", metadata={"foo": "string"}, ) assert_matches_type(LedgerCreateEntryResponse, ledger, path=["response"]) @@ -358,9 +366,9 @@ def test_method_create_entry_with_all_params_overload_5(self, client: Orb) -> No @parametrize def test_raw_response_create_entry_overload_5(self, client: Orb) -> None: response = client.customers.credits.ledger.with_raw_response.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) @@ -372,9 +380,9 @@ def test_raw_response_create_entry_overload_5(self, client: Orb) -> None: @parametrize def test_streaming_response_create_entry_overload_5(self, client: Orb) -> None: with client.customers.credits.ledger.with_streaming_response.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) as response: assert not response.is_closed @@ -389,16 +397,16 @@ def test_streaming_response_create_entry_overload_5(self, client: Orb) -> None: def test_path_params_create_entry_overload_5(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): client.customers.credits.ledger.with_raw_response.create_entry( - "", + customer_id="", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) @parametrize def test_method_create_entry_by_external_id_overload_1(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="increment", ) @@ -407,27 +415,39 @@ def test_method_create_entry_by_external_id_overload_1(self, client: Orb) -> Non @parametrize def test_method_create_entry_by_external_id_with_all_params_overload_1(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="increment", - currency="string", - description="string", + currency="currency", + description="description", effective_date=parse_datetime("2019-12-27T18:11:19.117Z"), expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), + filters=[ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], invoice_settings={ "auto_collection": True, + "custom_due_date": parse_date("2019-12-27"), + "invoice_date": parse_date("2019-12-27"), + "item_id": "item_id", + "mark_as_paid": True, + "memo": "memo", "net_terms": 0, - "memo": "string", + "require_successful_payment": True, }, metadata={"foo": "string"}, - per_unit_cost_basis="string", + per_unit_cost_basis="per_unit_cost_basis", ) assert_matches_type(LedgerCreateEntryByExternalIDResponse, ledger, path=["response"]) @parametrize def test_raw_response_create_entry_by_external_id_overload_1(self, client: Orb) -> None: response = client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="increment", ) @@ -440,7 +460,7 @@ def test_raw_response_create_entry_by_external_id_overload_1(self, client: Orb) @parametrize def test_streaming_response_create_entry_by_external_id_overload_1(self, client: Orb) -> None: with client.customers.credits.ledger.with_streaming_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="increment", ) as response: @@ -456,7 +476,7 @@ def test_streaming_response_create_entry_by_external_id_overload_1(self, client: def test_path_params_create_entry_by_external_id_overload_1(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "", + external_customer_id="", amount=0, entry_type="increment", ) @@ -464,7 +484,7 @@ def test_path_params_create_entry_by_external_id_overload_1(self, client: Orb) - @parametrize def test_method_create_entry_by_external_id_overload_2(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="decrement", ) @@ -473,11 +493,11 @@ def test_method_create_entry_by_external_id_overload_2(self, client: Orb) -> Non @parametrize def test_method_create_entry_by_external_id_with_all_params_overload_2(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="decrement", - currency="string", - description="string", + currency="currency", + description="description", metadata={"foo": "string"}, ) assert_matches_type(LedgerCreateEntryByExternalIDResponse, ledger, path=["response"]) @@ -485,7 +505,7 @@ def test_method_create_entry_by_external_id_with_all_params_overload_2(self, cli @parametrize def test_raw_response_create_entry_by_external_id_overload_2(self, client: Orb) -> None: response = client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="decrement", ) @@ -498,7 +518,7 @@ def test_raw_response_create_entry_by_external_id_overload_2(self, client: Orb) @parametrize def test_streaming_response_create_entry_by_external_id_overload_2(self, client: Orb) -> None: with client.customers.credits.ledger.with_streaming_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="decrement", ) as response: @@ -514,7 +534,7 @@ def test_streaming_response_create_entry_by_external_id_overload_2(self, client: def test_path_params_create_entry_by_external_id_overload_2(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "", + external_customer_id="", amount=0, entry_type="decrement", ) @@ -522,9 +542,8 @@ def test_path_params_create_entry_by_external_id_overload_2(self, client: Orb) - @parametrize def test_method_create_entry_by_external_id_overload_3(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) assert_matches_type(LedgerCreateEntryByExternalIDResponse, ledger, path=["response"]) @@ -532,14 +551,14 @@ def test_method_create_entry_by_external_id_overload_3(self, client: Orb) -> Non @parametrize def test_method_create_entry_by_external_id_with_all_params_overload_3(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), amount=0, - block_id="string", - currency="string", - description="string", + block_id="block_id", + currency="currency", + description="description", + expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), metadata={"foo": "string"}, ) assert_matches_type(LedgerCreateEntryByExternalIDResponse, ledger, path=["response"]) @@ -547,9 +566,8 @@ def test_method_create_entry_by_external_id_with_all_params_overload_3(self, cli @parametrize def test_raw_response_create_entry_by_external_id_overload_3(self, client: Orb) -> None: response = client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) @@ -561,9 +579,8 @@ def test_raw_response_create_entry_by_external_id_overload_3(self, client: Orb) @parametrize def test_streaming_response_create_entry_by_external_id_overload_3(self, client: Orb) -> None: with client.customers.credits.ledger.with_streaming_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) as response: assert not response.is_closed @@ -578,18 +595,17 @@ def test_streaming_response_create_entry_by_external_id_overload_3(self, client: def test_path_params_create_entry_by_external_id_overload_3(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "", + external_customer_id="", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) @parametrize def test_method_create_entry_by_external_id_overload_4(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) assert_matches_type(LedgerCreateEntryByExternalIDResponse, ledger, path=["response"]) @@ -597,12 +613,12 @@ def test_method_create_entry_by_external_id_overload_4(self, client: Orb) -> Non @parametrize def test_method_create_entry_by_external_id_with_all_params_overload_4(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", - currency="string", - description="string", + currency="currency", + description="description", metadata={"foo": "string"}, void_reason="refund", ) @@ -611,9 +627,9 @@ def test_method_create_entry_by_external_id_with_all_params_overload_4(self, cli @parametrize def test_raw_response_create_entry_by_external_id_overload_4(self, client: Orb) -> None: response = client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) @@ -625,9 +641,9 @@ def test_raw_response_create_entry_by_external_id_overload_4(self, client: Orb) @parametrize def test_streaming_response_create_entry_by_external_id_overload_4(self, client: Orb) -> None: with client.customers.credits.ledger.with_streaming_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) as response: assert not response.is_closed @@ -642,18 +658,18 @@ def test_streaming_response_create_entry_by_external_id_overload_4(self, client: def test_path_params_create_entry_by_external_id_overload_4(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "", + external_customer_id="", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) @parametrize def test_method_create_entry_by_external_id_overload_5(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) assert_matches_type(LedgerCreateEntryByExternalIDResponse, ledger, path=["response"]) @@ -661,12 +677,12 @@ def test_method_create_entry_by_external_id_overload_5(self, client: Orb) -> Non @parametrize def test_method_create_entry_by_external_id_with_all_params_overload_5(self, client: Orb) -> None: ledger = client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", - currency="string", - description="string", + currency="currency", + description="description", metadata={"foo": "string"}, ) assert_matches_type(LedgerCreateEntryByExternalIDResponse, ledger, path=["response"]) @@ -674,9 +690,9 @@ def test_method_create_entry_by_external_id_with_all_params_overload_5(self, cli @parametrize def test_raw_response_create_entry_by_external_id_overload_5(self, client: Orb) -> None: response = client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) @@ -688,9 +704,9 @@ def test_raw_response_create_entry_by_external_id_overload_5(self, client: Orb) @parametrize def test_streaming_response_create_entry_by_external_id_overload_5(self, client: Orb) -> None: with client.customers.credits.ledger.with_streaming_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) as response: assert not response.is_closed @@ -705,40 +721,40 @@ def test_streaming_response_create_entry_by_external_id_overload_5(self, client: def test_path_params_create_entry_by_external_id_overload_5(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "", + external_customer_id="", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) @parametrize def test_method_list_by_external_id(self, client: Orb) -> None: ledger = client.customers.credits.ledger.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert_matches_type(SyncPage[LedgerListByExternalIDResponse], ledger, path=["response"]) @parametrize def test_method_list_by_external_id_with_all_params(self, client: Orb) -> None: ledger = client.customers.credits.ledger.list_by_external_id( - "string", + external_customer_id="external_customer_id", created_at_gt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), - currency="string", - cursor="string", + currency="currency", + cursor="cursor", entry_status="committed", entry_type="increment", - limit=0, - minimum_amount="string", + limit=1, + minimum_amount="minimum_amount", ) assert_matches_type(SyncPage[LedgerListByExternalIDResponse], ledger, path=["response"]) @parametrize def test_raw_response_list_by_external_id(self, client: Orb) -> None: response = client.customers.credits.ledger.with_raw_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert response.is_closed is True @@ -749,7 +765,7 @@ def test_raw_response_list_by_external_id(self, client: Orb) -> None: @parametrize def test_streaming_response_list_by_external_id(self, client: Orb) -> None: with client.customers.credits.ledger.with_streaming_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -763,41 +779,43 @@ def test_streaming_response_list_by_external_id(self, client: Orb) -> None: def test_path_params_list_by_external_id(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): client.customers.credits.ledger.with_raw_response.list_by_external_id( - "", + external_customer_id="", ) class TestAsyncLedger: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.list( - "string", + customer_id="customer_id", ) assert_matches_type(AsyncPage[LedgerListResponse], ledger, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.list( - "string", + customer_id="customer_id", created_at_gt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), - currency="string", - cursor="string", + currency="currency", + cursor="cursor", entry_status="committed", entry_type="increment", - limit=0, - minimum_amount="string", + limit=1, + minimum_amount="minimum_amount", ) assert_matches_type(AsyncPage[LedgerListResponse], ledger, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.ledger.with_raw_response.list( - "string", + customer_id="customer_id", ) assert response.is_closed is True @@ -808,7 +826,7 @@ async def test_raw_response_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.ledger.with_streaming_response.list( - "string", + customer_id="customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -822,13 +840,13 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: async def test_path_params_list(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): await async_client.customers.credits.ledger.with_raw_response.list( - "", + customer_id="", ) @parametrize async def test_method_create_entry_overload_1(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="increment", ) @@ -837,27 +855,39 @@ async def test_method_create_entry_overload_1(self, async_client: AsyncOrb) -> N @parametrize async def test_method_create_entry_with_all_params_overload_1(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="increment", - currency="string", - description="string", + currency="currency", + description="description", effective_date=parse_datetime("2019-12-27T18:11:19.117Z"), expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), + filters=[ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], invoice_settings={ "auto_collection": True, + "custom_due_date": parse_date("2019-12-27"), + "invoice_date": parse_date("2019-12-27"), + "item_id": "item_id", + "mark_as_paid": True, + "memo": "memo", "net_terms": 0, - "memo": "string", + "require_successful_payment": True, }, metadata={"foo": "string"}, - per_unit_cost_basis="string", + per_unit_cost_basis="per_unit_cost_basis", ) assert_matches_type(LedgerCreateEntryResponse, ledger, path=["response"]) @parametrize async def test_raw_response_create_entry_overload_1(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.ledger.with_raw_response.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="increment", ) @@ -870,7 +900,7 @@ async def test_raw_response_create_entry_overload_1(self, async_client: AsyncOrb @parametrize async def test_streaming_response_create_entry_overload_1(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.ledger.with_streaming_response.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="increment", ) as response: @@ -886,7 +916,7 @@ async def test_streaming_response_create_entry_overload_1(self, async_client: As async def test_path_params_create_entry_overload_1(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): await async_client.customers.credits.ledger.with_raw_response.create_entry( - "", + customer_id="", amount=0, entry_type="increment", ) @@ -894,7 +924,7 @@ async def test_path_params_create_entry_overload_1(self, async_client: AsyncOrb) @parametrize async def test_method_create_entry_overload_2(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="decrement", ) @@ -903,11 +933,11 @@ async def test_method_create_entry_overload_2(self, async_client: AsyncOrb) -> N @parametrize async def test_method_create_entry_with_all_params_overload_2(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="decrement", - currency="string", - description="string", + currency="currency", + description="description", metadata={"foo": "string"}, ) assert_matches_type(LedgerCreateEntryResponse, ledger, path=["response"]) @@ -915,7 +945,7 @@ async def test_method_create_entry_with_all_params_overload_2(self, async_client @parametrize async def test_raw_response_create_entry_overload_2(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.ledger.with_raw_response.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="decrement", ) @@ -928,7 +958,7 @@ async def test_raw_response_create_entry_overload_2(self, async_client: AsyncOrb @parametrize async def test_streaming_response_create_entry_overload_2(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.ledger.with_streaming_response.create_entry( - "string", + customer_id="customer_id", amount=0, entry_type="decrement", ) as response: @@ -944,7 +974,7 @@ async def test_streaming_response_create_entry_overload_2(self, async_client: As async def test_path_params_create_entry_overload_2(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): await async_client.customers.credits.ledger.with_raw_response.create_entry( - "", + customer_id="", amount=0, entry_type="decrement", ) @@ -952,9 +982,8 @@ async def test_path_params_create_entry_overload_2(self, async_client: AsyncOrb) @parametrize async def test_method_create_entry_overload_3(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) assert_matches_type(LedgerCreateEntryResponse, ledger, path=["response"]) @@ -962,14 +991,14 @@ async def test_method_create_entry_overload_3(self, async_client: AsyncOrb) -> N @parametrize async def test_method_create_entry_with_all_params_overload_3(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), amount=0, - block_id="string", - currency="string", - description="string", + block_id="block_id", + currency="currency", + description="description", + expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), metadata={"foo": "string"}, ) assert_matches_type(LedgerCreateEntryResponse, ledger, path=["response"]) @@ -977,9 +1006,8 @@ async def test_method_create_entry_with_all_params_overload_3(self, async_client @parametrize async def test_raw_response_create_entry_overload_3(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.ledger.with_raw_response.create_entry( - "string", + customer_id="customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) @@ -991,9 +1019,8 @@ async def test_raw_response_create_entry_overload_3(self, async_client: AsyncOrb @parametrize async def test_streaming_response_create_entry_overload_3(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.ledger.with_streaming_response.create_entry( - "string", + customer_id="customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) as response: assert not response.is_closed @@ -1008,18 +1035,17 @@ async def test_streaming_response_create_entry_overload_3(self, async_client: As async def test_path_params_create_entry_overload_3(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): await async_client.customers.credits.ledger.with_raw_response.create_entry( - "", + customer_id="", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) @parametrize async def test_method_create_entry_overload_4(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) assert_matches_type(LedgerCreateEntryResponse, ledger, path=["response"]) @@ -1027,12 +1053,12 @@ async def test_method_create_entry_overload_4(self, async_client: AsyncOrb) -> N @parametrize async def test_method_create_entry_with_all_params_overload_4(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", - currency="string", - description="string", + currency="currency", + description="description", metadata={"foo": "string"}, void_reason="refund", ) @@ -1041,9 +1067,9 @@ async def test_method_create_entry_with_all_params_overload_4(self, async_client @parametrize async def test_raw_response_create_entry_overload_4(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.ledger.with_raw_response.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) @@ -1055,9 +1081,9 @@ async def test_raw_response_create_entry_overload_4(self, async_client: AsyncOrb @parametrize async def test_streaming_response_create_entry_overload_4(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.ledger.with_streaming_response.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) as response: assert not response.is_closed @@ -1072,18 +1098,18 @@ async def test_streaming_response_create_entry_overload_4(self, async_client: As async def test_path_params_create_entry_overload_4(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): await async_client.customers.credits.ledger.with_raw_response.create_entry( - "", + customer_id="", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) @parametrize async def test_method_create_entry_overload_5(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) assert_matches_type(LedgerCreateEntryResponse, ledger, path=["response"]) @@ -1091,12 +1117,12 @@ async def test_method_create_entry_overload_5(self, async_client: AsyncOrb) -> N @parametrize async def test_method_create_entry_with_all_params_overload_5(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", - currency="string", - description="string", + currency="currency", + description="description", metadata={"foo": "string"}, ) assert_matches_type(LedgerCreateEntryResponse, ledger, path=["response"]) @@ -1104,9 +1130,9 @@ async def test_method_create_entry_with_all_params_overload_5(self, async_client @parametrize async def test_raw_response_create_entry_overload_5(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.ledger.with_raw_response.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) @@ -1118,9 +1144,9 @@ async def test_raw_response_create_entry_overload_5(self, async_client: AsyncOrb @parametrize async def test_streaming_response_create_entry_overload_5(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.ledger.with_streaming_response.create_entry( - "string", + customer_id="customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) as response: assert not response.is_closed @@ -1135,16 +1161,16 @@ async def test_streaming_response_create_entry_overload_5(self, async_client: As async def test_path_params_create_entry_overload_5(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): await async_client.customers.credits.ledger.with_raw_response.create_entry( - "", + customer_id="", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) @parametrize async def test_method_create_entry_by_external_id_overload_1(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="increment", ) @@ -1153,27 +1179,39 @@ async def test_method_create_entry_by_external_id_overload_1(self, async_client: @parametrize async def test_method_create_entry_by_external_id_with_all_params_overload_1(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="increment", - currency="string", - description="string", + currency="currency", + description="description", effective_date=parse_datetime("2019-12-27T18:11:19.117Z"), expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), + filters=[ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], invoice_settings={ "auto_collection": True, + "custom_due_date": parse_date("2019-12-27"), + "invoice_date": parse_date("2019-12-27"), + "item_id": "item_id", + "mark_as_paid": True, + "memo": "memo", "net_terms": 0, - "memo": "string", + "require_successful_payment": True, }, metadata={"foo": "string"}, - per_unit_cost_basis="string", + per_unit_cost_basis="per_unit_cost_basis", ) assert_matches_type(LedgerCreateEntryByExternalIDResponse, ledger, path=["response"]) @parametrize async def test_raw_response_create_entry_by_external_id_overload_1(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="increment", ) @@ -1186,7 +1224,7 @@ async def test_raw_response_create_entry_by_external_id_overload_1(self, async_c @parametrize async def test_streaming_response_create_entry_by_external_id_overload_1(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.ledger.with_streaming_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="increment", ) as response: @@ -1202,7 +1240,7 @@ async def test_streaming_response_create_entry_by_external_id_overload_1(self, a async def test_path_params_create_entry_by_external_id_overload_1(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): await async_client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "", + external_customer_id="", amount=0, entry_type="increment", ) @@ -1210,7 +1248,7 @@ async def test_path_params_create_entry_by_external_id_overload_1(self, async_cl @parametrize async def test_method_create_entry_by_external_id_overload_2(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="decrement", ) @@ -1219,11 +1257,11 @@ async def test_method_create_entry_by_external_id_overload_2(self, async_client: @parametrize async def test_method_create_entry_by_external_id_with_all_params_overload_2(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="decrement", - currency="string", - description="string", + currency="currency", + description="description", metadata={"foo": "string"}, ) assert_matches_type(LedgerCreateEntryByExternalIDResponse, ledger, path=["response"]) @@ -1231,7 +1269,7 @@ async def test_method_create_entry_by_external_id_with_all_params_overload_2(sel @parametrize async def test_raw_response_create_entry_by_external_id_overload_2(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="decrement", ) @@ -1244,7 +1282,7 @@ async def test_raw_response_create_entry_by_external_id_overload_2(self, async_c @parametrize async def test_streaming_response_create_entry_by_external_id_overload_2(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.ledger.with_streaming_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, entry_type="decrement", ) as response: @@ -1260,7 +1298,7 @@ async def test_streaming_response_create_entry_by_external_id_overload_2(self, a async def test_path_params_create_entry_by_external_id_overload_2(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): await async_client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "", + external_customer_id="", amount=0, entry_type="decrement", ) @@ -1268,9 +1306,8 @@ async def test_path_params_create_entry_by_external_id_overload_2(self, async_cl @parametrize async def test_method_create_entry_by_external_id_overload_3(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) assert_matches_type(LedgerCreateEntryByExternalIDResponse, ledger, path=["response"]) @@ -1278,14 +1315,14 @@ async def test_method_create_entry_by_external_id_overload_3(self, async_client: @parametrize async def test_method_create_entry_by_external_id_with_all_params_overload_3(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), amount=0, - block_id="string", - currency="string", - description="string", + block_id="block_id", + currency="currency", + description="description", + expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), metadata={"foo": "string"}, ) assert_matches_type(LedgerCreateEntryByExternalIDResponse, ledger, path=["response"]) @@ -1293,9 +1330,8 @@ async def test_method_create_entry_by_external_id_with_all_params_overload_3(sel @parametrize async def test_raw_response_create_entry_by_external_id_overload_3(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) @@ -1307,9 +1343,8 @@ async def test_raw_response_create_entry_by_external_id_overload_3(self, async_c @parametrize async def test_streaming_response_create_entry_by_external_id_overload_3(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.ledger.with_streaming_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) as response: assert not response.is_closed @@ -1324,18 +1359,17 @@ async def test_streaming_response_create_entry_by_external_id_overload_3(self, a async def test_path_params_create_entry_by_external_id_overload_3(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): await async_client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "", + external_customer_id="", entry_type="expiration_change", - expiry_date=parse_datetime("2019-12-27T18:11:19.117Z"), target_expiry_date=parse_date("2019-12-27"), ) @parametrize async def test_method_create_entry_by_external_id_overload_4(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) assert_matches_type(LedgerCreateEntryByExternalIDResponse, ledger, path=["response"]) @@ -1343,12 +1377,12 @@ async def test_method_create_entry_by_external_id_overload_4(self, async_client: @parametrize async def test_method_create_entry_by_external_id_with_all_params_overload_4(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", - currency="string", - description="string", + currency="currency", + description="description", metadata={"foo": "string"}, void_reason="refund", ) @@ -1357,9 +1391,9 @@ async def test_method_create_entry_by_external_id_with_all_params_overload_4(sel @parametrize async def test_raw_response_create_entry_by_external_id_overload_4(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) @@ -1371,9 +1405,9 @@ async def test_raw_response_create_entry_by_external_id_overload_4(self, async_c @parametrize async def test_streaming_response_create_entry_by_external_id_overload_4(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.ledger.with_streaming_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) as response: assert not response.is_closed @@ -1388,18 +1422,18 @@ async def test_streaming_response_create_entry_by_external_id_overload_4(self, a async def test_path_params_create_entry_by_external_id_overload_4(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): await async_client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "", + external_customer_id="", amount=0, - block_id="string", + block_id="block_id", entry_type="void", ) @parametrize async def test_method_create_entry_by_external_id_overload_5(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) assert_matches_type(LedgerCreateEntryByExternalIDResponse, ledger, path=["response"]) @@ -1407,12 +1441,12 @@ async def test_method_create_entry_by_external_id_overload_5(self, async_client: @parametrize async def test_method_create_entry_by_external_id_with_all_params_overload_5(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", - currency="string", - description="string", + currency="currency", + description="description", metadata={"foo": "string"}, ) assert_matches_type(LedgerCreateEntryByExternalIDResponse, ledger, path=["response"]) @@ -1420,9 +1454,9 @@ async def test_method_create_entry_by_external_id_with_all_params_overload_5(sel @parametrize async def test_raw_response_create_entry_by_external_id_overload_5(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) @@ -1434,9 +1468,9 @@ async def test_raw_response_create_entry_by_external_id_overload_5(self, async_c @parametrize async def test_streaming_response_create_entry_by_external_id_overload_5(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.ledger.with_streaming_response.create_entry_by_external_id( - "string", + external_customer_id="external_customer_id", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) as response: assert not response.is_closed @@ -1451,40 +1485,40 @@ async def test_streaming_response_create_entry_by_external_id_overload_5(self, a async def test_path_params_create_entry_by_external_id_overload_5(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): await async_client.customers.credits.ledger.with_raw_response.create_entry_by_external_id( - "", + external_customer_id="", amount=0, - block_id="string", + block_id="block_id", entry_type="amendment", ) @parametrize async def test_method_list_by_external_id(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert_matches_type(AsyncPage[LedgerListByExternalIDResponse], ledger, path=["response"]) @parametrize async def test_method_list_by_external_id_with_all_params(self, async_client: AsyncOrb) -> None: ledger = await async_client.customers.credits.ledger.list_by_external_id( - "string", + external_customer_id="external_customer_id", created_at_gt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), - currency="string", - cursor="string", + currency="currency", + cursor="cursor", entry_status="committed", entry_type="increment", - limit=0, - minimum_amount="string", + limit=1, + minimum_amount="minimum_amount", ) assert_matches_type(AsyncPage[LedgerListByExternalIDResponse], ledger, path=["response"]) @parametrize async def test_raw_response_list_by_external_id(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.ledger.with_raw_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert response.is_closed is True @@ -1495,7 +1529,7 @@ async def test_raw_response_list_by_external_id(self, async_client: AsyncOrb) -> @parametrize async def test_streaming_response_list_by_external_id(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.ledger.with_streaming_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1509,5 +1543,5 @@ async def test_streaming_response_list_by_external_id(self, async_client: AsyncO async def test_path_params_list_by_external_id(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): await async_client.customers.credits.ledger.with_raw_response.list_by_external_id( - "", + external_customer_id="", ) diff --git a/tests/api_resources/customers/credits/test_top_ups.py b/tests/api_resources/customers/credits/test_top_ups.py index 66cbcac4..728f90b7 100644 --- a/tests/api_resources/customers/credits/test_top_ups.py +++ b/tests/api_resources/customers/credits/test_top_ups.py @@ -8,6 +8,7 @@ import pytest from orb import Orb, AsyncOrb +from orb._utils import parse_datetime from tests.utils import assert_matches_type from orb.pagination import SyncPage, AsyncPage from orb.types.customers.credits import ( @@ -26,31 +27,33 @@ class TestTopUps: @parametrize def test_method_create(self, client: Orb) -> None: top_up = client.customers.credits.top_ups.create( - "string", - amount="string", - currency="string", + customer_id="customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) assert_matches_type(TopUpCreateResponse, top_up, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: Orb) -> None: top_up = client.customers.credits.top_ups.create( - "string", - amount="string", - currency="string", + customer_id="customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, - "memo": "string", + "memo": "memo", + "require_successful_payment": True, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", + active_from=parse_datetime("2019-12-27T18:11:19.117Z"), expires_after=0, expires_after_unit="day", ) @@ -59,15 +62,15 @@ def test_method_create_with_all_params(self, client: Orb) -> None: @parametrize def test_raw_response_create(self, client: Orb) -> None: response = client.customers.credits.top_ups.with_raw_response.create( - "string", - amount="string", - currency="string", + customer_id="customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) assert response.is_closed is True @@ -78,15 +81,15 @@ def test_raw_response_create(self, client: Orb) -> None: @parametrize def test_streaming_response_create(self, client: Orb) -> None: with client.customers.credits.top_ups.with_streaming_response.create( - "string", - amount="string", - currency="string", + customer_id="customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -100,37 +103,37 @@ def test_streaming_response_create(self, client: Orb) -> None: def test_path_params_create(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): client.customers.credits.top_ups.with_raw_response.create( - "", - amount="string", - currency="string", + customer_id="", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) @parametrize def test_method_list(self, client: Orb) -> None: top_up = client.customers.credits.top_ups.list( - "string", + customer_id="customer_id", ) assert_matches_type(SyncPage[TopUpListResponse], top_up, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: Orb) -> None: top_up = client.customers.credits.top_ups.list( - "string", - cursor="string", - limit=0, + customer_id="customer_id", + cursor="cursor", + limit=1, ) assert_matches_type(SyncPage[TopUpListResponse], top_up, path=["response"]) @parametrize def test_raw_response_list(self, client: Orb) -> None: response = client.customers.credits.top_ups.with_raw_response.list( - "string", + customer_id="customer_id", ) assert response.is_closed is True @@ -141,7 +144,7 @@ def test_raw_response_list(self, client: Orb) -> None: @parametrize def test_streaming_response_list(self, client: Orb) -> None: with client.customers.credits.top_ups.with_streaming_response.list( - "string", + customer_id="customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -155,22 +158,22 @@ def test_streaming_response_list(self, client: Orb) -> None: def test_path_params_list(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): client.customers.credits.top_ups.with_raw_response.list( - "", + customer_id="", ) @parametrize def test_method_delete(self, client: Orb) -> None: top_up = client.customers.credits.top_ups.delete( - "string", - customer_id="string", + top_up_id="top_up_id", + customer_id="customer_id", ) assert top_up is None @parametrize def test_raw_response_delete(self, client: Orb) -> None: response = client.customers.credits.top_ups.with_raw_response.delete( - "string", - customer_id="string", + top_up_id="top_up_id", + customer_id="customer_id", ) assert response.is_closed is True @@ -181,8 +184,8 @@ def test_raw_response_delete(self, client: Orb) -> None: @parametrize def test_streaming_response_delete(self, client: Orb) -> None: with client.customers.credits.top_ups.with_streaming_response.delete( - "string", - customer_id="string", + top_up_id="top_up_id", + customer_id="customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -196,44 +199,46 @@ def test_streaming_response_delete(self, client: Orb) -> None: def test_path_params_delete(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): client.customers.credits.top_ups.with_raw_response.delete( - "string", + top_up_id="top_up_id", customer_id="", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `top_up_id` but received ''"): client.customers.credits.top_ups.with_raw_response.delete( - "", - customer_id="string", + top_up_id="", + customer_id="customer_id", ) @parametrize def test_method_create_by_external_id(self, client: Orb) -> None: top_up = client.customers.credits.top_ups.create_by_external_id( - "string", - amount="string", - currency="string", + external_customer_id="external_customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) assert_matches_type(TopUpCreateByExternalIDResponse, top_up, path=["response"]) @parametrize def test_method_create_by_external_id_with_all_params(self, client: Orb) -> None: top_up = client.customers.credits.top_ups.create_by_external_id( - "string", - amount="string", - currency="string", + external_customer_id="external_customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, - "memo": "string", + "memo": "memo", + "require_successful_payment": True, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", + active_from=parse_datetime("2019-12-27T18:11:19.117Z"), expires_after=0, expires_after_unit="day", ) @@ -242,15 +247,15 @@ def test_method_create_by_external_id_with_all_params(self, client: Orb) -> None @parametrize def test_raw_response_create_by_external_id(self, client: Orb) -> None: response = client.customers.credits.top_ups.with_raw_response.create_by_external_id( - "string", - amount="string", - currency="string", + external_customer_id="external_customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) assert response.is_closed is True @@ -261,15 +266,15 @@ def test_raw_response_create_by_external_id(self, client: Orb) -> None: @parametrize def test_streaming_response_create_by_external_id(self, client: Orb) -> None: with client.customers.credits.top_ups.with_streaming_response.create_by_external_id( - "string", - amount="string", - currency="string", + external_customer_id="external_customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -283,30 +288,30 @@ def test_streaming_response_create_by_external_id(self, client: Orb) -> None: def test_path_params_create_by_external_id(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): client.customers.credits.top_ups.with_raw_response.create_by_external_id( - "", - amount="string", - currency="string", + external_customer_id="", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) @parametrize def test_method_delete_by_external_id(self, client: Orb) -> None: top_up = client.customers.credits.top_ups.delete_by_external_id( - "string", - external_customer_id="string", + top_up_id="top_up_id", + external_customer_id="external_customer_id", ) assert top_up is None @parametrize def test_raw_response_delete_by_external_id(self, client: Orb) -> None: response = client.customers.credits.top_ups.with_raw_response.delete_by_external_id( - "string", - external_customer_id="string", + top_up_id="top_up_id", + external_customer_id="external_customer_id", ) assert response.is_closed is True @@ -317,8 +322,8 @@ def test_raw_response_delete_by_external_id(self, client: Orb) -> None: @parametrize def test_streaming_response_delete_by_external_id(self, client: Orb) -> None: with client.customers.credits.top_ups.with_streaming_response.delete_by_external_id( - "string", - external_customer_id="string", + top_up_id="top_up_id", + external_customer_id="external_customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -332,36 +337,36 @@ def test_streaming_response_delete_by_external_id(self, client: Orb) -> None: def test_path_params_delete_by_external_id(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): client.customers.credits.top_ups.with_raw_response.delete_by_external_id( - "string", + top_up_id="top_up_id", external_customer_id="", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `top_up_id` but received ''"): client.customers.credits.top_ups.with_raw_response.delete_by_external_id( - "", - external_customer_id="string", + top_up_id="", + external_customer_id="external_customer_id", ) @parametrize def test_method_list_by_external_id(self, client: Orb) -> None: top_up = client.customers.credits.top_ups.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert_matches_type(SyncPage[TopUpListByExternalIDResponse], top_up, path=["response"]) @parametrize def test_method_list_by_external_id_with_all_params(self, client: Orb) -> None: top_up = client.customers.credits.top_ups.list_by_external_id( - "string", - cursor="string", - limit=0, + external_customer_id="external_customer_id", + cursor="cursor", + limit=1, ) assert_matches_type(SyncPage[TopUpListByExternalIDResponse], top_up, path=["response"]) @parametrize def test_raw_response_list_by_external_id(self, client: Orb) -> None: response = client.customers.credits.top_ups.with_raw_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert response.is_closed is True @@ -372,7 +377,7 @@ def test_raw_response_list_by_external_id(self, client: Orb) -> None: @parametrize def test_streaming_response_list_by_external_id(self, client: Orb) -> None: with client.customers.credits.top_ups.with_streaming_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -386,41 +391,45 @@ def test_streaming_response_list_by_external_id(self, client: Orb) -> None: def test_path_params_list_by_external_id(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): client.customers.credits.top_ups.with_raw_response.list_by_external_id( - "", + external_customer_id="", ) class TestAsyncTopUps: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOrb) -> None: top_up = await async_client.customers.credits.top_ups.create( - "string", - amount="string", - currency="string", + customer_id="customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) assert_matches_type(TopUpCreateResponse, top_up, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> None: top_up = await async_client.customers.credits.top_ups.create( - "string", - amount="string", - currency="string", + customer_id="customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, - "memo": "string", + "memo": "memo", + "require_successful_payment": True, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", + active_from=parse_datetime("2019-12-27T18:11:19.117Z"), expires_after=0, expires_after_unit="day", ) @@ -429,15 +438,15 @@ 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.credits.top_ups.with_raw_response.create( - "string", - amount="string", - currency="string", + customer_id="customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) assert response.is_closed is True @@ -448,15 +457,15 @@ 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.credits.top_ups.with_streaming_response.create( - "string", - amount="string", - currency="string", + customer_id="customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -470,37 +479,37 @@ async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: async def test_path_params_create(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): await async_client.customers.credits.top_ups.with_raw_response.create( - "", - amount="string", - currency="string", + customer_id="", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) @parametrize async def test_method_list(self, async_client: AsyncOrb) -> None: top_up = await async_client.customers.credits.top_ups.list( - "string", + customer_id="customer_id", ) assert_matches_type(AsyncPage[TopUpListResponse], top_up, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: top_up = await async_client.customers.credits.top_ups.list( - "string", - cursor="string", - limit=0, + customer_id="customer_id", + cursor="cursor", + limit=1, ) assert_matches_type(AsyncPage[TopUpListResponse], top_up, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.top_ups.with_raw_response.list( - "string", + customer_id="customer_id", ) assert response.is_closed is True @@ -511,7 +520,7 @@ async def test_raw_response_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.top_ups.with_streaming_response.list( - "string", + customer_id="customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -525,22 +534,22 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: async def test_path_params_list(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): await async_client.customers.credits.top_ups.with_raw_response.list( - "", + customer_id="", ) @parametrize async def test_method_delete(self, async_client: AsyncOrb) -> None: top_up = await async_client.customers.credits.top_ups.delete( - "string", - customer_id="string", + top_up_id="top_up_id", + customer_id="customer_id", ) assert top_up is None @parametrize async def test_raw_response_delete(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.top_ups.with_raw_response.delete( - "string", - customer_id="string", + top_up_id="top_up_id", + customer_id="customer_id", ) assert response.is_closed is True @@ -551,8 +560,8 @@ async def test_raw_response_delete(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_delete(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.top_ups.with_streaming_response.delete( - "string", - customer_id="string", + top_up_id="top_up_id", + customer_id="customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -566,44 +575,46 @@ async def test_streaming_response_delete(self, async_client: AsyncOrb) -> None: async def test_path_params_delete(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): await async_client.customers.credits.top_ups.with_raw_response.delete( - "string", + top_up_id="top_up_id", customer_id="", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `top_up_id` but received ''"): await async_client.customers.credits.top_ups.with_raw_response.delete( - "", - customer_id="string", + top_up_id="", + customer_id="customer_id", ) @parametrize async def test_method_create_by_external_id(self, async_client: AsyncOrb) -> None: top_up = await async_client.customers.credits.top_ups.create_by_external_id( - "string", - amount="string", - currency="string", + external_customer_id="external_customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) assert_matches_type(TopUpCreateByExternalIDResponse, top_up, path=["response"]) @parametrize async def test_method_create_by_external_id_with_all_params(self, async_client: AsyncOrb) -> None: top_up = await async_client.customers.credits.top_ups.create_by_external_id( - "string", - amount="string", - currency="string", + external_customer_id="external_customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, - "memo": "string", + "memo": "memo", + "require_successful_payment": True, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", + active_from=parse_datetime("2019-12-27T18:11:19.117Z"), expires_after=0, expires_after_unit="day", ) @@ -612,15 +623,15 @@ async def test_method_create_by_external_id_with_all_params(self, async_client: @parametrize async def test_raw_response_create_by_external_id(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.top_ups.with_raw_response.create_by_external_id( - "string", - amount="string", - currency="string", + external_customer_id="external_customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) assert response.is_closed is True @@ -631,15 +642,15 @@ async def test_raw_response_create_by_external_id(self, async_client: AsyncOrb) @parametrize async def test_streaming_response_create_by_external_id(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.top_ups.with_streaming_response.create_by_external_id( - "string", - amount="string", - currency="string", + external_customer_id="external_customer_id", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -653,30 +664,30 @@ async def test_streaming_response_create_by_external_id(self, async_client: Asyn async def test_path_params_create_by_external_id(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): await async_client.customers.credits.top_ups.with_raw_response.create_by_external_id( - "", - amount="string", - currency="string", + external_customer_id="", + amount="amount", + currency="currency", invoice_settings={ "auto_collection": True, "net_terms": 0, }, - per_unit_cost_basis="string", - threshold="string", + per_unit_cost_basis="per_unit_cost_basis", + threshold="threshold", ) @parametrize async def test_method_delete_by_external_id(self, async_client: AsyncOrb) -> None: top_up = await async_client.customers.credits.top_ups.delete_by_external_id( - "string", - external_customer_id="string", + top_up_id="top_up_id", + external_customer_id="external_customer_id", ) assert top_up is None @parametrize async def test_raw_response_delete_by_external_id(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.top_ups.with_raw_response.delete_by_external_id( - "string", - external_customer_id="string", + top_up_id="top_up_id", + external_customer_id="external_customer_id", ) assert response.is_closed is True @@ -687,8 +698,8 @@ async def test_raw_response_delete_by_external_id(self, async_client: AsyncOrb) @parametrize async def test_streaming_response_delete_by_external_id(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.top_ups.with_streaming_response.delete_by_external_id( - "string", - external_customer_id="string", + top_up_id="top_up_id", + external_customer_id="external_customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -702,36 +713,36 @@ async def test_streaming_response_delete_by_external_id(self, async_client: Asyn async def test_path_params_delete_by_external_id(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): await async_client.customers.credits.top_ups.with_raw_response.delete_by_external_id( - "string", + top_up_id="top_up_id", external_customer_id="", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `top_up_id` but received ''"): await async_client.customers.credits.top_ups.with_raw_response.delete_by_external_id( - "", - external_customer_id="string", + top_up_id="", + external_customer_id="external_customer_id", ) @parametrize async def test_method_list_by_external_id(self, async_client: AsyncOrb) -> None: top_up = await async_client.customers.credits.top_ups.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert_matches_type(AsyncPage[TopUpListByExternalIDResponse], top_up, path=["response"]) @parametrize async def test_method_list_by_external_id_with_all_params(self, async_client: AsyncOrb) -> None: top_up = await async_client.customers.credits.top_ups.list_by_external_id( - "string", - cursor="string", - limit=0, + external_customer_id="external_customer_id", + cursor="cursor", + limit=1, ) assert_matches_type(AsyncPage[TopUpListByExternalIDResponse], top_up, path=["response"]) @parametrize async def test_raw_response_list_by_external_id(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.top_ups.with_raw_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert response.is_closed is True @@ -742,7 +753,7 @@ async def test_raw_response_list_by_external_id(self, async_client: AsyncOrb) -> @parametrize async def test_streaming_response_list_by_external_id(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.top_ups.with_streaming_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -756,5 +767,5 @@ async def test_streaming_response_list_by_external_id(self, async_client: AsyncO async def test_path_params_list_by_external_id(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): await async_client.customers.credits.top_ups.with_raw_response.list_by_external_id( - "", + external_customer_id="", ) diff --git a/tests/api_resources/customers/test_balance_transactions.py b/tests/api_resources/customers/test_balance_transactions.py index 098fd754..054ffd79 100644 --- a/tests/api_resources/customers/test_balance_transactions.py +++ b/tests/api_resources/customers/test_balance_transactions.py @@ -25,8 +25,8 @@ class TestBalanceTransactions: @parametrize def test_method_create(self, client: Orb) -> None: balance_transaction = client.customers.balance_transactions.create( - "string", - amount="string", + customer_id="customer_id", + amount="amount", type="increment", ) assert_matches_type(BalanceTransactionCreateResponse, balance_transaction, path=["response"]) @@ -34,18 +34,18 @@ def test_method_create(self, client: Orb) -> None: @parametrize def test_method_create_with_all_params(self, client: Orb) -> None: balance_transaction = client.customers.balance_transactions.create( - "string", - amount="string", + customer_id="customer_id", + amount="amount", type="increment", - description="string", + description="description", ) assert_matches_type(BalanceTransactionCreateResponse, balance_transaction, path=["response"]) @parametrize def test_raw_response_create(self, client: Orb) -> None: response = client.customers.balance_transactions.with_raw_response.create( - "string", - amount="string", + customer_id="customer_id", + amount="amount", type="increment", ) @@ -57,8 +57,8 @@ def test_raw_response_create(self, client: Orb) -> None: @parametrize def test_streaming_response_create(self, client: Orb) -> None: with client.customers.balance_transactions.with_streaming_response.create( - "string", - amount="string", + customer_id="customer_id", + amount="amount", type="increment", ) as response: assert not response.is_closed @@ -73,24 +73,24 @@ def test_streaming_response_create(self, client: Orb) -> None: def test_path_params_create(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): client.customers.balance_transactions.with_raw_response.create( - "", - amount="string", + customer_id="", + amount="amount", type="increment", ) @parametrize def test_method_list(self, client: Orb) -> None: balance_transaction = client.customers.balance_transactions.list( - "string", + customer_id="customer_id", ) assert_matches_type(SyncPage[BalanceTransactionListResponse], balance_transaction, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: Orb) -> None: balance_transaction = client.customers.balance_transactions.list( - "string", - cursor="string", - limit=0, + customer_id="customer_id", + cursor="cursor", + limit=1, operation_time_gt=parse_datetime("2019-12-27T18:11:19.117Z"), operation_time_gte=parse_datetime("2019-12-27T18:11:19.117Z"), operation_time_lt=parse_datetime("2019-12-27T18:11:19.117Z"), @@ -101,7 +101,7 @@ def test_method_list_with_all_params(self, client: Orb) -> None: @parametrize def test_raw_response_list(self, client: Orb) -> None: response = client.customers.balance_transactions.with_raw_response.list( - "string", + customer_id="customer_id", ) assert response.is_closed is True @@ -112,7 +112,7 @@ def test_raw_response_list(self, client: Orb) -> None: @parametrize def test_streaming_response_list(self, client: Orb) -> None: with client.customers.balance_transactions.with_streaming_response.list( - "string", + customer_id="customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -126,18 +126,20 @@ def test_streaming_response_list(self, client: Orb) -> None: def test_path_params_list(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): client.customers.balance_transactions.with_raw_response.list( - "", + customer_id="", ) class TestAsyncBalanceTransactions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOrb) -> None: balance_transaction = await async_client.customers.balance_transactions.create( - "string", - amount="string", + customer_id="customer_id", + amount="amount", type="increment", ) assert_matches_type(BalanceTransactionCreateResponse, balance_transaction, path=["response"]) @@ -145,18 +147,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: balance_transaction = await async_client.customers.balance_transactions.create( - "string", - amount="string", + customer_id="customer_id", + amount="amount", type="increment", - description="string", + description="description", ) assert_matches_type(BalanceTransactionCreateResponse, balance_transaction, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncOrb) -> None: response = await async_client.customers.balance_transactions.with_raw_response.create( - "string", - amount="string", + customer_id="customer_id", + amount="amount", type="increment", ) @@ -168,8 +170,8 @@ 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.balance_transactions.with_streaming_response.create( - "string", - amount="string", + customer_id="customer_id", + amount="amount", type="increment", ) as response: assert not response.is_closed @@ -184,24 +186,24 @@ async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: async def test_path_params_create(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): await async_client.customers.balance_transactions.with_raw_response.create( - "", - amount="string", + customer_id="", + amount="amount", type="increment", ) @parametrize async def test_method_list(self, async_client: AsyncOrb) -> None: balance_transaction = await async_client.customers.balance_transactions.list( - "string", + customer_id="customer_id", ) assert_matches_type(AsyncPage[BalanceTransactionListResponse], balance_transaction, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: balance_transaction = await async_client.customers.balance_transactions.list( - "string", - cursor="string", - limit=0, + customer_id="customer_id", + cursor="cursor", + limit=1, operation_time_gt=parse_datetime("2019-12-27T18:11:19.117Z"), operation_time_gte=parse_datetime("2019-12-27T18:11:19.117Z"), operation_time_lt=parse_datetime("2019-12-27T18:11:19.117Z"), @@ -212,7 +214,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None @parametrize async def test_raw_response_list(self, async_client: AsyncOrb) -> None: response = await async_client.customers.balance_transactions.with_raw_response.list( - "string", + customer_id="customer_id", ) assert response.is_closed is True @@ -223,7 +225,7 @@ async def test_raw_response_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: async with async_client.customers.balance_transactions.with_streaming_response.list( - "string", + customer_id="customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -237,5 +239,5 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: async def test_path_params_list(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): await async_client.customers.balance_transactions.with_raw_response.list( - "", + customer_id="", ) diff --git a/tests/api_resources/customers/test_costs.py b/tests/api_resources/customers/test_costs.py index 9d8fa5e8..dfab25e6 100644 --- a/tests/api_resources/customers/test_costs.py +++ b/tests/api_resources/customers/test_costs.py @@ -24,14 +24,15 @@ class TestCosts: @parametrize def test_method_list(self, client: Orb) -> None: cost = client.customers.costs.list( - "string", + customer_id="customer_id", ) assert_matches_type(CostListResponse, cost, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: Orb) -> None: cost = client.customers.costs.list( - "string", + customer_id="customer_id", + currency="currency", timeframe_end=parse_datetime("2022-03-01T05:00:00Z"), timeframe_start=parse_datetime("2022-02-01T05:00:00Z"), view_mode="periodic", @@ -41,7 +42,7 @@ def test_method_list_with_all_params(self, client: Orb) -> None: @parametrize def test_raw_response_list(self, client: Orb) -> None: response = client.customers.costs.with_raw_response.list( - "string", + customer_id="customer_id", ) assert response.is_closed is True @@ -52,7 +53,7 @@ def test_raw_response_list(self, client: Orb) -> None: @parametrize def test_streaming_response_list(self, client: Orb) -> None: with client.customers.costs.with_streaming_response.list( - "string", + customer_id="customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -66,20 +67,21 @@ def test_streaming_response_list(self, client: Orb) -> None: def test_path_params_list(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): client.customers.costs.with_raw_response.list( - "", + customer_id="", ) @parametrize def test_method_list_by_external_id(self, client: Orb) -> None: cost = client.customers.costs.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert_matches_type(CostListByExternalIDResponse, cost, path=["response"]) @parametrize def test_method_list_by_external_id_with_all_params(self, client: Orb) -> None: cost = client.customers.costs.list_by_external_id( - "string", + external_customer_id="external_customer_id", + currency="currency", timeframe_end=parse_datetime("2022-03-01T05:00:00Z"), timeframe_start=parse_datetime("2022-02-01T05:00:00Z"), view_mode="periodic", @@ -89,7 +91,7 @@ def test_method_list_by_external_id_with_all_params(self, client: Orb) -> None: @parametrize def test_raw_response_list_by_external_id(self, client: Orb) -> None: response = client.customers.costs.with_raw_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert response.is_closed is True @@ -100,7 +102,7 @@ def test_raw_response_list_by_external_id(self, client: Orb) -> None: @parametrize def test_streaming_response_list_by_external_id(self, client: Orb) -> None: with client.customers.costs.with_streaming_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -114,24 +116,27 @@ def test_streaming_response_list_by_external_id(self, client: Orb) -> None: def test_path_params_list_by_external_id(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): client.customers.costs.with_raw_response.list_by_external_id( - "", + external_customer_id="", ) class TestAsyncCosts: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncOrb) -> None: cost = await async_client.customers.costs.list( - "string", + customer_id="customer_id", ) assert_matches_type(CostListResponse, cost, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: cost = await async_client.customers.costs.list( - "string", + customer_id="customer_id", + currency="currency", timeframe_end=parse_datetime("2022-03-01T05:00:00Z"), timeframe_start=parse_datetime("2022-02-01T05:00:00Z"), view_mode="periodic", @@ -141,7 +146,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None @parametrize async def test_raw_response_list(self, async_client: AsyncOrb) -> None: response = await async_client.customers.costs.with_raw_response.list( - "string", + customer_id="customer_id", ) assert response.is_closed is True @@ -152,7 +157,7 @@ async def test_raw_response_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: async with async_client.customers.costs.with_streaming_response.list( - "string", + customer_id="customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -166,20 +171,21 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: async def test_path_params_list(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): await async_client.customers.costs.with_raw_response.list( - "", + customer_id="", ) @parametrize async def test_method_list_by_external_id(self, async_client: AsyncOrb) -> None: cost = await async_client.customers.costs.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert_matches_type(CostListByExternalIDResponse, cost, path=["response"]) @parametrize async def test_method_list_by_external_id_with_all_params(self, async_client: AsyncOrb) -> None: cost = await async_client.customers.costs.list_by_external_id( - "string", + external_customer_id="external_customer_id", + currency="currency", timeframe_end=parse_datetime("2022-03-01T05:00:00Z"), timeframe_start=parse_datetime("2022-02-01T05:00:00Z"), view_mode="periodic", @@ -189,7 +195,7 @@ async def test_method_list_by_external_id_with_all_params(self, async_client: As @parametrize async def test_raw_response_list_by_external_id(self, async_client: AsyncOrb) -> None: response = await async_client.customers.costs.with_raw_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert response.is_closed is True @@ -200,7 +206,7 @@ async def test_raw_response_list_by_external_id(self, async_client: AsyncOrb) -> @parametrize async def test_streaming_response_list_by_external_id(self, async_client: AsyncOrb) -> None: async with async_client.customers.costs.with_streaming_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -214,5 +220,5 @@ async def test_streaming_response_list_by_external_id(self, async_client: AsyncO async def test_path_params_list_by_external_id(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): await async_client.customers.costs.with_raw_response.list_by_external_id( - "", + external_customer_id="", ) diff --git a/tests/api_resources/customers/test_credits.py b/tests/api_resources/customers/test_credits.py index 15b8d021..20303c88 100644 --- a/tests/api_resources/customers/test_credits.py +++ b/tests/api_resources/customers/test_credits.py @@ -8,6 +8,7 @@ import pytest from orb import Orb, AsyncOrb +from orb._utils import parse_datetime from tests.utils import assert_matches_type from orb.pagination import SyncPage, AsyncPage from orb.types.customers import ( @@ -24,24 +25,29 @@ class TestCredits: @parametrize def test_method_list(self, client: Orb) -> None: credit = client.customers.credits.list( - "string", + customer_id="customer_id", ) assert_matches_type(SyncPage[CreditListResponse], credit, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: Orb) -> None: credit = client.customers.credits.list( - "string", - currency="string", - cursor="string", - limit=0, + customer_id="customer_id", + currency="currency", + cursor="cursor", + effective_date_gt=parse_datetime("2019-12-27T18:11:19.117Z"), + effective_date_gte=parse_datetime("2019-12-27T18:11:19.117Z"), + effective_date_lt=parse_datetime("2019-12-27T18:11:19.117Z"), + effective_date_lte=parse_datetime("2019-12-27T18:11:19.117Z"), + include_all_blocks=True, + limit=1, ) assert_matches_type(SyncPage[CreditListResponse], credit, path=["response"]) @parametrize def test_raw_response_list(self, client: Orb) -> None: response = client.customers.credits.with_raw_response.list( - "string", + customer_id="customer_id", ) assert response.is_closed is True @@ -52,7 +58,7 @@ def test_raw_response_list(self, client: Orb) -> None: @parametrize def test_streaming_response_list(self, client: Orb) -> None: with client.customers.credits.with_streaming_response.list( - "string", + customer_id="customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -66,30 +72,35 @@ def test_streaming_response_list(self, client: Orb) -> None: def test_path_params_list(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): client.customers.credits.with_raw_response.list( - "", + customer_id="", ) @parametrize def test_method_list_by_external_id(self, client: Orb) -> None: credit = client.customers.credits.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert_matches_type(SyncPage[CreditListByExternalIDResponse], credit, path=["response"]) @parametrize def test_method_list_by_external_id_with_all_params(self, client: Orb) -> None: credit = client.customers.credits.list_by_external_id( - "string", - currency="string", - cursor="string", - limit=0, + external_customer_id="external_customer_id", + currency="currency", + cursor="cursor", + effective_date_gt=parse_datetime("2019-12-27T18:11:19.117Z"), + effective_date_gte=parse_datetime("2019-12-27T18:11:19.117Z"), + effective_date_lt=parse_datetime("2019-12-27T18:11:19.117Z"), + effective_date_lte=parse_datetime("2019-12-27T18:11:19.117Z"), + include_all_blocks=True, + limit=1, ) assert_matches_type(SyncPage[CreditListByExternalIDResponse], credit, path=["response"]) @parametrize def test_raw_response_list_by_external_id(self, client: Orb) -> None: response = client.customers.credits.with_raw_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert response.is_closed is True @@ -100,7 +111,7 @@ def test_raw_response_list_by_external_id(self, client: Orb) -> None: @parametrize def test_streaming_response_list_by_external_id(self, client: Orb) -> None: with client.customers.credits.with_streaming_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -114,34 +125,41 @@ def test_streaming_response_list_by_external_id(self, client: Orb) -> None: def test_path_params_list_by_external_id(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): client.customers.credits.with_raw_response.list_by_external_id( - "", + external_customer_id="", ) class TestAsyncCredits: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncOrb) -> None: credit = await async_client.customers.credits.list( - "string", + customer_id="customer_id", ) assert_matches_type(AsyncPage[CreditListResponse], credit, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: credit = await async_client.customers.credits.list( - "string", - currency="string", - cursor="string", - limit=0, + customer_id="customer_id", + currency="currency", + cursor="cursor", + effective_date_gt=parse_datetime("2019-12-27T18:11:19.117Z"), + effective_date_gte=parse_datetime("2019-12-27T18:11:19.117Z"), + effective_date_lt=parse_datetime("2019-12-27T18:11:19.117Z"), + effective_date_lte=parse_datetime("2019-12-27T18:11:19.117Z"), + include_all_blocks=True, + limit=1, ) assert_matches_type(AsyncPage[CreditListResponse], credit, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.with_raw_response.list( - "string", + customer_id="customer_id", ) assert response.is_closed is True @@ -152,7 +170,7 @@ async def test_raw_response_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.with_streaming_response.list( - "string", + customer_id="customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -166,30 +184,35 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: async def test_path_params_list(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): await async_client.customers.credits.with_raw_response.list( - "", + customer_id="", ) @parametrize async def test_method_list_by_external_id(self, async_client: AsyncOrb) -> None: credit = await async_client.customers.credits.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert_matches_type(AsyncPage[CreditListByExternalIDResponse], credit, path=["response"]) @parametrize async def test_method_list_by_external_id_with_all_params(self, async_client: AsyncOrb) -> None: credit = await async_client.customers.credits.list_by_external_id( - "string", - currency="string", - cursor="string", - limit=0, + external_customer_id="external_customer_id", + currency="currency", + cursor="cursor", + effective_date_gt=parse_datetime("2019-12-27T18:11:19.117Z"), + effective_date_gte=parse_datetime("2019-12-27T18:11:19.117Z"), + effective_date_lt=parse_datetime("2019-12-27T18:11:19.117Z"), + effective_date_lte=parse_datetime("2019-12-27T18:11:19.117Z"), + include_all_blocks=True, + limit=1, ) assert_matches_type(AsyncPage[CreditListByExternalIDResponse], credit, path=["response"]) @parametrize async def test_raw_response_list_by_external_id(self, async_client: AsyncOrb) -> None: response = await async_client.customers.credits.with_raw_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) assert response.is_closed is True @@ -200,7 +223,7 @@ async def test_raw_response_list_by_external_id(self, async_client: AsyncOrb) -> @parametrize async def test_streaming_response_list_by_external_id(self, async_client: AsyncOrb) -> None: async with async_client.customers.credits.with_streaming_response.list_by_external_id( - "string", + external_customer_id="external_customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -214,5 +237,5 @@ async def test_streaming_response_list_by_external_id(self, async_client: AsyncO async def test_path_params_list_by_external_id(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): await async_client.customers.credits.with_raw_response.list_by_external_id( - "", + external_customer_id="", ) diff --git a/tests/api_resources/customers/test_usage.py b/tests/api_resources/customers/test_usage.py deleted file mode 100644 index b933101e..00000000 --- a/tests/api_resources/customers/test_usage.py +++ /dev/null @@ -1,578 +0,0 @@ -# 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.customers import ( - UsageUpdateResponse, - UsageUpdateByExternalIDResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestUsage: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_update(self, client: Orb) -> None: - usage = client.customers.usage.update( - "string", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) - assert_matches_type(UsageUpdateResponse, usage, path=["response"]) - - @parametrize - def test_method_update_with_all_params(self, client: Orb) -> None: - usage = client.customers.usage.update( - "string", - events=[ - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), - timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(UsageUpdateResponse, usage, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Orb) -> None: - response = client.customers.usage.with_raw_response.update( - "string", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = response.parse() - assert_matches_type(UsageUpdateResponse, usage, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Orb) -> None: - with client.customers.usage.with_streaming_response.update( - "string", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = response.parse() - assert_matches_type(UsageUpdateResponse, usage, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_update(self, client: Orb) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.customers.usage.with_raw_response.update( - "", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) - - @parametrize - def test_method_update_by_external_id(self, client: Orb) -> None: - usage = client.customers.usage.update_by_external_id( - "string", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) - assert_matches_type(UsageUpdateByExternalIDResponse, usage, path=["response"]) - - @parametrize - def test_method_update_by_external_id_with_all_params(self, client: Orb) -> None: - usage = client.customers.usage.update_by_external_id( - "string", - events=[ - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), - timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(UsageUpdateByExternalIDResponse, usage, path=["response"]) - - @parametrize - def test_raw_response_update_by_external_id(self, client: Orb) -> None: - response = client.customers.usage.with_raw_response.update_by_external_id( - "string", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = response.parse() - assert_matches_type(UsageUpdateByExternalIDResponse, usage, path=["response"]) - - @parametrize - def test_streaming_response_update_by_external_id(self, client: Orb) -> None: - with client.customers.usage.with_streaming_response.update_by_external_id( - "string", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = response.parse() - assert_matches_type(UsageUpdateByExternalIDResponse, usage, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_update_by_external_id(self, client: Orb) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.customers.usage.with_raw_response.update_by_external_id( - "", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) - - -class TestAsyncUsage: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - async def test_method_update(self, async_client: AsyncOrb) -> None: - usage = await async_client.customers.usage.update( - "string", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) - assert_matches_type(UsageUpdateResponse, usage, path=["response"]) - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> None: - usage = await async_client.customers.usage.update( - "string", - events=[ - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), - timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(UsageUpdateResponse, usage, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncOrb) -> None: - response = await async_client.customers.usage.with_raw_response.update( - "string", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = response.parse() - assert_matches_type(UsageUpdateResponse, usage, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: - async with async_client.customers.usage.with_streaming_response.update( - "string", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = await response.parse() - assert_matches_type(UsageUpdateResponse, usage, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_update(self, async_client: AsyncOrb) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.customers.usage.with_raw_response.update( - "", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) - - @parametrize - async def test_method_update_by_external_id(self, async_client: AsyncOrb) -> None: - usage = await async_client.customers.usage.update_by_external_id( - "string", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) - assert_matches_type(UsageUpdateByExternalIDResponse, usage, path=["response"]) - - @parametrize - async def test_method_update_by_external_id_with_all_params(self, async_client: AsyncOrb) -> None: - usage = await async_client.customers.usage.update_by_external_id( - "string", - events=[ - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), - timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(UsageUpdateByExternalIDResponse, usage, path=["response"]) - - @parametrize - async def test_raw_response_update_by_external_id(self, async_client: AsyncOrb) -> None: - response = await async_client.customers.usage.with_raw_response.update_by_external_id( - "string", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = response.parse() - assert_matches_type(UsageUpdateByExternalIDResponse, usage, path=["response"]) - - @parametrize - async def test_streaming_response_update_by_external_id(self, async_client: AsyncOrb) -> None: - async with async_client.customers.usage.with_streaming_response.update_by_external_id( - "string", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = await response.parse() - assert_matches_type(UsageUpdateByExternalIDResponse, usage, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_update_by_external_id(self, async_client: AsyncOrb) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.customers.usage.with_raw_response.update_by_external_id( - "", - events=[ - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - }, - ], - ) diff --git a/tests/api_resources/dimensional_price_groups/__init__.py b/tests/api_resources/dimensional_price_groups/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/dimensional_price_groups/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/dimensional_price_groups/test_external_dimensional_price_group_id.py b/tests/api_resources/dimensional_price_groups/test_external_dimensional_price_group_id.py new file mode 100644 index 00000000..e035df9e --- /dev/null +++ b/tests/api_resources/dimensional_price_groups/test_external_dimensional_price_group_id.py @@ -0,0 +1,224 @@ +# 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.types import DimensionalPriceGroup +from tests.utils import assert_matches_type + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestExternalDimensionalPriceGroupID: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: Orb) -> None: + external_dimensional_price_group_id = ( + client.dimensional_price_groups.external_dimensional_price_group_id.retrieve( + "external_dimensional_price_group_id", + ) + ) + assert_matches_type(DimensionalPriceGroup, external_dimensional_price_group_id, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: Orb) -> None: + response = client.dimensional_price_groups.external_dimensional_price_group_id.with_raw_response.retrieve( + "external_dimensional_price_group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_dimensional_price_group_id = response.parse() + assert_matches_type(DimensionalPriceGroup, external_dimensional_price_group_id, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: Orb) -> None: + with client.dimensional_price_groups.external_dimensional_price_group_id.with_streaming_response.retrieve( + "external_dimensional_price_group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_dimensional_price_group_id = response.parse() + assert_matches_type(DimensionalPriceGroup, external_dimensional_price_group_id, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: Orb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `external_dimensional_price_group_id` but received ''" + ): + client.dimensional_price_groups.external_dimensional_price_group_id.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: Orb) -> None: + external_dimensional_price_group_id = ( + client.dimensional_price_groups.external_dimensional_price_group_id.update( + path_external_dimensional_price_group_id="external_dimensional_price_group_id", + ) + ) + assert_matches_type(DimensionalPriceGroup, external_dimensional_price_group_id, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Orb) -> None: + external_dimensional_price_group_id = ( + client.dimensional_price_groups.external_dimensional_price_group_id.update( + path_external_dimensional_price_group_id="external_dimensional_price_group_id", + body_external_dimensional_price_group_id="external_dimensional_price_group_id", + metadata={"foo": "string"}, + ) + ) + assert_matches_type(DimensionalPriceGroup, external_dimensional_price_group_id, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Orb) -> None: + response = client.dimensional_price_groups.external_dimensional_price_group_id.with_raw_response.update( + path_external_dimensional_price_group_id="external_dimensional_price_group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_dimensional_price_group_id = response.parse() + assert_matches_type(DimensionalPriceGroup, external_dimensional_price_group_id, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Orb) -> None: + with client.dimensional_price_groups.external_dimensional_price_group_id.with_streaming_response.update( + path_external_dimensional_price_group_id="external_dimensional_price_group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_dimensional_price_group_id = response.parse() + assert_matches_type(DimensionalPriceGroup, external_dimensional_price_group_id, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Orb) -> None: + with pytest.raises( + ValueError, + match=r"Expected a non-empty value for `path_external_dimensional_price_group_id` but received ''", + ): + client.dimensional_price_groups.external_dimensional_price_group_id.with_raw_response.update( + path_external_dimensional_price_group_id="", + ) + + +class TestAsyncExternalDimensionalPriceGroupID: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOrb) -> None: + external_dimensional_price_group_id = ( + await async_client.dimensional_price_groups.external_dimensional_price_group_id.retrieve( + "external_dimensional_price_group_id", + ) + ) + assert_matches_type(DimensionalPriceGroup, external_dimensional_price_group_id, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOrb) -> None: + response = ( + await async_client.dimensional_price_groups.external_dimensional_price_group_id.with_raw_response.retrieve( + "external_dimensional_price_group_id", + ) + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_dimensional_price_group_id = response.parse() + assert_matches_type(DimensionalPriceGroup, external_dimensional_price_group_id, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOrb) -> None: + async with ( + async_client.dimensional_price_groups.external_dimensional_price_group_id.with_streaming_response.retrieve( + "external_dimensional_price_group_id", + ) + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_dimensional_price_group_id = await response.parse() + assert_matches_type(DimensionalPriceGroup, external_dimensional_price_group_id, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOrb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `external_dimensional_price_group_id` but received ''" + ): + await async_client.dimensional_price_groups.external_dimensional_price_group_id.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOrb) -> None: + external_dimensional_price_group_id = ( + await async_client.dimensional_price_groups.external_dimensional_price_group_id.update( + path_external_dimensional_price_group_id="external_dimensional_price_group_id", + ) + ) + assert_matches_type(DimensionalPriceGroup, external_dimensional_price_group_id, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> None: + external_dimensional_price_group_id = ( + await async_client.dimensional_price_groups.external_dimensional_price_group_id.update( + path_external_dimensional_price_group_id="external_dimensional_price_group_id", + body_external_dimensional_price_group_id="external_dimensional_price_group_id", + metadata={"foo": "string"}, + ) + ) + assert_matches_type(DimensionalPriceGroup, external_dimensional_price_group_id, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOrb) -> None: + response = ( + await async_client.dimensional_price_groups.external_dimensional_price_group_id.with_raw_response.update( + path_external_dimensional_price_group_id="external_dimensional_price_group_id", + ) + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_dimensional_price_group_id = response.parse() + assert_matches_type(DimensionalPriceGroup, external_dimensional_price_group_id, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: + async with ( + async_client.dimensional_price_groups.external_dimensional_price_group_id.with_streaming_response.update( + path_external_dimensional_price_group_id="external_dimensional_price_group_id", + ) + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_dimensional_price_group_id = await response.parse() + assert_matches_type(DimensionalPriceGroup, external_dimensional_price_group_id, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOrb) -> None: + with pytest.raises( + ValueError, + match=r"Expected a non-empty value for `path_external_dimensional_price_group_id` but received ''", + ): + await async_client.dimensional_price_groups.external_dimensional_price_group_id.with_raw_response.update( + path_external_dimensional_price_group_id="", + ) diff --git a/tests/api_resources/events/test_backfills.py b/tests/api_resources/events/test_backfills.py index f8547ef9..9cabc90c 100644 --- a/tests/api_resources/events/test_backfills.py +++ b/tests/api_resources/events/test_backfills.py @@ -39,8 +39,9 @@ def test_method_create_with_all_params(self, client: Orb) -> None: timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), close_time=parse_datetime("2019-12-27T18:11:19.117Z"), - customer_id="string", - external_customer_id="string", + customer_id="customer_id", + deprecation_filter="my_numeric_property > 100 AND my_other_property = 'bar'", + external_customer_id="external_customer_id", replace_existing_events=True, ) assert_matches_type(BackfillCreateResponse, backfill, path=["response"]) @@ -79,8 +80,8 @@ def test_method_list(self, client: Orb) -> None: @parametrize def test_method_list_with_all_params(self, client: Orb) -> None: backfill = client.events.backfills.list( - cursor="string", - limit=0, + cursor="cursor", + limit=1, ) assert_matches_type(SyncPage[BackfillListResponse], backfill, path=["response"]) @@ -107,14 +108,14 @@ def test_streaming_response_list(self, client: Orb) -> None: @parametrize def test_method_close(self, client: Orb) -> None: backfill = client.events.backfills.close( - "string", + "backfill_id", ) assert_matches_type(BackfillCloseResponse, backfill, path=["response"]) @parametrize def test_raw_response_close(self, client: Orb) -> None: response = client.events.backfills.with_raw_response.close( - "string", + "backfill_id", ) assert response.is_closed is True @@ -125,7 +126,7 @@ def test_raw_response_close(self, client: Orb) -> None: @parametrize def test_streaming_response_close(self, client: Orb) -> None: with client.events.backfills.with_streaming_response.close( - "string", + "backfill_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -145,14 +146,14 @@ def test_path_params_close(self, client: Orb) -> None: @parametrize def test_method_fetch(self, client: Orb) -> None: backfill = client.events.backfills.fetch( - "string", + "backfill_id", ) assert_matches_type(BackfillFetchResponse, backfill, path=["response"]) @parametrize def test_raw_response_fetch(self, client: Orb) -> None: response = client.events.backfills.with_raw_response.fetch( - "string", + "backfill_id", ) assert response.is_closed is True @@ -163,7 +164,7 @@ def test_raw_response_fetch(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch(self, client: Orb) -> None: with client.events.backfills.with_streaming_response.fetch( - "string", + "backfill_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -183,14 +184,14 @@ def test_path_params_fetch(self, client: Orb) -> None: @parametrize def test_method_revert(self, client: Orb) -> None: backfill = client.events.backfills.revert( - "string", + "backfill_id", ) assert_matches_type(BackfillRevertResponse, backfill, path=["response"]) @parametrize def test_raw_response_revert(self, client: Orb) -> None: response = client.events.backfills.with_raw_response.revert( - "string", + "backfill_id", ) assert response.is_closed is True @@ -201,7 +202,7 @@ def test_raw_response_revert(self, client: Orb) -> None: @parametrize def test_streaming_response_revert(self, client: Orb) -> None: with client.events.backfills.with_streaming_response.revert( - "string", + "backfill_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -220,7 +221,9 @@ def test_path_params_revert(self, client: Orb) -> None: class TestAsyncBackfills: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOrb) -> None: @@ -236,8 +239,9 @@ async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> No timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), close_time=parse_datetime("2019-12-27T18:11:19.117Z"), - customer_id="string", - external_customer_id="string", + customer_id="customer_id", + deprecation_filter="my_numeric_property > 100 AND my_other_property = 'bar'", + external_customer_id="external_customer_id", replace_existing_events=True, ) assert_matches_type(BackfillCreateResponse, backfill, path=["response"]) @@ -276,8 +280,8 @@ async def test_method_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: backfill = await async_client.events.backfills.list( - cursor="string", - limit=0, + cursor="cursor", + limit=1, ) assert_matches_type(AsyncPage[BackfillListResponse], backfill, path=["response"]) @@ -304,14 +308,14 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_close(self, async_client: AsyncOrb) -> None: backfill = await async_client.events.backfills.close( - "string", + "backfill_id", ) assert_matches_type(BackfillCloseResponse, backfill, path=["response"]) @parametrize async def test_raw_response_close(self, async_client: AsyncOrb) -> None: response = await async_client.events.backfills.with_raw_response.close( - "string", + "backfill_id", ) assert response.is_closed is True @@ -322,7 +326,7 @@ async def test_raw_response_close(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_close(self, async_client: AsyncOrb) -> None: async with async_client.events.backfills.with_streaming_response.close( - "string", + "backfill_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -342,14 +346,14 @@ async def test_path_params_close(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_fetch(self, async_client: AsyncOrb) -> None: backfill = await async_client.events.backfills.fetch( - "string", + "backfill_id", ) assert_matches_type(BackfillFetchResponse, backfill, path=["response"]) @parametrize async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: response = await async_client.events.backfills.with_raw_response.fetch( - "string", + "backfill_id", ) assert response.is_closed is True @@ -360,7 +364,7 @@ async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_fetch(self, async_client: AsyncOrb) -> None: async with async_client.events.backfills.with_streaming_response.fetch( - "string", + "backfill_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -380,14 +384,14 @@ async def test_path_params_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_revert(self, async_client: AsyncOrb) -> None: backfill = await async_client.events.backfills.revert( - "string", + "backfill_id", ) assert_matches_type(BackfillRevertResponse, backfill, path=["response"]) @parametrize async def test_raw_response_revert(self, async_client: AsyncOrb) -> None: response = await async_client.events.backfills.with_raw_response.revert( - "string", + "backfill_id", ) assert response.is_closed is True @@ -398,7 +402,7 @@ async def test_raw_response_revert(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_revert(self, async_client: AsyncOrb) -> None: async with async_client.events.backfills.with_streaming_response.revert( - "string", + "backfill_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/events/test_volume.py b/tests/api_resources/events/test_volume.py new file mode 100644 index 00000000..87ef4772 --- /dev/null +++ b/tests/api_resources/events/test_volume.py @@ -0,0 +1,107 @@ +# 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, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @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/licenses/__init__.py b/tests/api_resources/licenses/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/licenses/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/licenses/test_external_licenses.py b/tests/api_resources/licenses/test_external_licenses.py new file mode 100644 index 00000000..a90febb7 --- /dev/null +++ b/tests/api_resources/licenses/test_external_licenses.py @@ -0,0 +1,145 @@ +# 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_date +from tests.utils import assert_matches_type +from orb.types.licenses import ExternalLicenseGetUsageResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestExternalLicenses: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_usage(self, client: Orb) -> None: + external_license = client.licenses.external_licenses.get_usage( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + assert_matches_type(ExternalLicenseGetUsageResponse, external_license, path=["response"]) + + @parametrize + def test_method_get_usage_with_all_params(self, client: Orb) -> None: + external_license = client.licenses.external_licenses.get_usage( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + cursor="cursor", + end_date=parse_date("2019-12-27"), + group_by="group_by", + limit=1, + start_date=parse_date("2019-12-27"), + ) + assert_matches_type(ExternalLicenseGetUsageResponse, external_license, path=["response"]) + + @parametrize + def test_raw_response_get_usage(self, client: Orb) -> None: + response = client.licenses.external_licenses.with_raw_response.get_usage( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_license = response.parse() + assert_matches_type(ExternalLicenseGetUsageResponse, external_license, path=["response"]) + + @parametrize + def test_streaming_response_get_usage(self, client: Orb) -> None: + with client.licenses.external_licenses.with_streaming_response.get_usage( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_license = response.parse() + assert_matches_type(ExternalLicenseGetUsageResponse, external_license, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_usage(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_license_id` but received ''"): + client.licenses.external_licenses.with_raw_response.get_usage( + external_license_id="", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + + +class TestAsyncExternalLicenses: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_usage(self, async_client: AsyncOrb) -> None: + external_license = await async_client.licenses.external_licenses.get_usage( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + assert_matches_type(ExternalLicenseGetUsageResponse, external_license, path=["response"]) + + @parametrize + async def test_method_get_usage_with_all_params(self, async_client: AsyncOrb) -> None: + external_license = await async_client.licenses.external_licenses.get_usage( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + cursor="cursor", + end_date=parse_date("2019-12-27"), + group_by="group_by", + limit=1, + start_date=parse_date("2019-12-27"), + ) + assert_matches_type(ExternalLicenseGetUsageResponse, external_license, path=["response"]) + + @parametrize + async def test_raw_response_get_usage(self, async_client: AsyncOrb) -> None: + response = await async_client.licenses.external_licenses.with_raw_response.get_usage( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_license = response.parse() + assert_matches_type(ExternalLicenseGetUsageResponse, external_license, path=["response"]) + + @parametrize + async def test_streaming_response_get_usage(self, async_client: AsyncOrb) -> None: + async with async_client.licenses.external_licenses.with_streaming_response.get_usage( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_license = await response.parse() + assert_matches_type(ExternalLicenseGetUsageResponse, external_license, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_usage(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_license_id` but received ''"): + await async_client.licenses.external_licenses.with_raw_response.get_usage( + external_license_id="", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) diff --git a/tests/api_resources/licenses/test_usage.py b/tests/api_resources/licenses/test_usage.py new file mode 100644 index 00000000..d5d158e0 --- /dev/null +++ b/tests/api_resources/licenses/test_usage.py @@ -0,0 +1,222 @@ +# 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_date +from tests.utils import assert_matches_type +from orb.types.licenses import ( + UsageGetUsageResponse, + UsageGetAllUsageResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestUsage: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_all_usage(self, client: Orb) -> None: + usage = client.licenses.usage.get_all_usage( + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + assert_matches_type(UsageGetAllUsageResponse, usage, path=["response"]) + + @parametrize + def test_method_get_all_usage_with_all_params(self, client: Orb) -> None: + usage = client.licenses.usage.get_all_usage( + license_type_id="license_type_id", + subscription_id="subscription_id", + cursor="cursor", + end_date=parse_date("2019-12-27"), + group_by="group_by", + limit=1, + start_date=parse_date("2019-12-27"), + ) + assert_matches_type(UsageGetAllUsageResponse, usage, path=["response"]) + + @parametrize + def test_raw_response_get_all_usage(self, client: Orb) -> None: + response = client.licenses.usage.with_raw_response.get_all_usage( + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageGetAllUsageResponse, usage, path=["response"]) + + @parametrize + def test_streaming_response_get_all_usage(self, client: Orb) -> None: + with client.licenses.usage.with_streaming_response.get_all_usage( + license_type_id="license_type_id", + subscription_id="subscription_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = response.parse() + assert_matches_type(UsageGetAllUsageResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_usage(self, client: Orb) -> None: + usage = client.licenses.usage.get_usage( + license_id="license_id", + ) + assert_matches_type(UsageGetUsageResponse, usage, path=["response"]) + + @parametrize + def test_method_get_usage_with_all_params(self, client: Orb) -> None: + usage = client.licenses.usage.get_usage( + license_id="license_id", + cursor="cursor", + end_date=parse_date("2019-12-27"), + group_by="group_by", + limit=1, + start_date=parse_date("2019-12-27"), + ) + assert_matches_type(UsageGetUsageResponse, usage, path=["response"]) + + @parametrize + def test_raw_response_get_usage(self, client: Orb) -> None: + response = client.licenses.usage.with_raw_response.get_usage( + license_id="license_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageGetUsageResponse, usage, path=["response"]) + + @parametrize + def test_streaming_response_get_usage(self, client: Orb) -> None: + with client.licenses.usage.with_streaming_response.get_usage( + license_id="license_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = response.parse() + assert_matches_type(UsageGetUsageResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_usage(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `license_id` but received ''"): + client.licenses.usage.with_raw_response.get_usage( + license_id="", + ) + + +class TestAsyncUsage: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_all_usage(self, async_client: AsyncOrb) -> None: + usage = await async_client.licenses.usage.get_all_usage( + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + assert_matches_type(UsageGetAllUsageResponse, usage, path=["response"]) + + @parametrize + async def test_method_get_all_usage_with_all_params(self, async_client: AsyncOrb) -> None: + usage = await async_client.licenses.usage.get_all_usage( + license_type_id="license_type_id", + subscription_id="subscription_id", + cursor="cursor", + end_date=parse_date("2019-12-27"), + group_by="group_by", + limit=1, + start_date=parse_date("2019-12-27"), + ) + assert_matches_type(UsageGetAllUsageResponse, usage, path=["response"]) + + @parametrize + async def test_raw_response_get_all_usage(self, async_client: AsyncOrb) -> None: + response = await async_client.licenses.usage.with_raw_response.get_all_usage( + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageGetAllUsageResponse, usage, path=["response"]) + + @parametrize + async def test_streaming_response_get_all_usage(self, async_client: AsyncOrb) -> None: + async with async_client.licenses.usage.with_streaming_response.get_all_usage( + license_type_id="license_type_id", + subscription_id="subscription_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = await response.parse() + assert_matches_type(UsageGetAllUsageResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_usage(self, async_client: AsyncOrb) -> None: + usage = await async_client.licenses.usage.get_usage( + license_id="license_id", + ) + assert_matches_type(UsageGetUsageResponse, usage, path=["response"]) + + @parametrize + async def test_method_get_usage_with_all_params(self, async_client: AsyncOrb) -> None: + usage = await async_client.licenses.usage.get_usage( + license_id="license_id", + cursor="cursor", + end_date=parse_date("2019-12-27"), + group_by="group_by", + limit=1, + start_date=parse_date("2019-12-27"), + ) + assert_matches_type(UsageGetUsageResponse, usage, path=["response"]) + + @parametrize + async def test_raw_response_get_usage(self, async_client: AsyncOrb) -> None: + response = await async_client.licenses.usage.with_raw_response.get_usage( + license_id="license_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage = response.parse() + assert_matches_type(UsageGetUsageResponse, usage, path=["response"]) + + @parametrize + async def test_streaming_response_get_usage(self, async_client: AsyncOrb) -> None: + async with async_client.licenses.usage.with_streaming_response.get_usage( + license_id="license_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage = await response.parse() + assert_matches_type(UsageGetUsageResponse, usage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_usage(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `license_id` but received ''"): + await async_client.licenses.usage.with_raw_response.get_usage( + license_id="", + ) diff --git a/tests/api_resources/plans/test_external_plan_id.py b/tests/api_resources/plans/test_external_plan_id.py index f28c7431..64838190 100644 --- a/tests/api_resources/plans/test_external_plan_id.py +++ b/tests/api_resources/plans/test_external_plan_id.py @@ -20,15 +20,16 @@ class TestExternalPlanID: @parametrize def test_method_update(self, client: Orb) -> None: external_plan_id = client.plans.external_plan_id.update( - "string", + other_external_plan_id="external_plan_id", ) assert_matches_type(Plan, external_plan_id, path=["response"]) @parametrize def test_method_update_with_all_params(self, client: Orb) -> None: external_plan_id = client.plans.external_plan_id.update( - "string", - external_plan_id="string", + other_external_plan_id="external_plan_id", + description="description", + external_plan_id="external_plan_id", metadata={"foo": "string"}, ) assert_matches_type(Plan, external_plan_id, path=["response"]) @@ -36,7 +37,7 @@ def test_method_update_with_all_params(self, client: Orb) -> None: @parametrize def test_raw_response_update(self, client: Orb) -> None: response = client.plans.external_plan_id.with_raw_response.update( - "string", + other_external_plan_id="external_plan_id", ) assert response.is_closed is True @@ -47,7 +48,7 @@ def test_raw_response_update(self, client: Orb) -> None: @parametrize def test_streaming_response_update(self, client: Orb) -> None: with client.plans.external_plan_id.with_streaming_response.update( - "string", + other_external_plan_id="external_plan_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -63,21 +64,20 @@ def test_path_params_update(self, client: Orb) -> None: ValueError, match=r"Expected a non-empty value for `other_external_plan_id` but received ''" ): client.plans.external_plan_id.with_raw_response.update( - "", - external_plan_id="", + other_external_plan_id="", ) @parametrize def test_method_fetch(self, client: Orb) -> None: external_plan_id = client.plans.external_plan_id.fetch( - "string", + "external_plan_id", ) assert_matches_type(Plan, external_plan_id, path=["response"]) @parametrize def test_raw_response_fetch(self, client: Orb) -> None: response = client.plans.external_plan_id.with_raw_response.fetch( - "string", + "external_plan_id", ) assert response.is_closed is True @@ -88,7 +88,7 @@ def test_raw_response_fetch(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch(self, client: Orb) -> None: with client.plans.external_plan_id.with_streaming_response.fetch( - "string", + "external_plan_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -107,20 +107,23 @@ def test_path_params_fetch(self, client: Orb) -> None: class TestAsyncExternalPlanID: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_update(self, async_client: AsyncOrb) -> None: external_plan_id = await async_client.plans.external_plan_id.update( - "string", + other_external_plan_id="external_plan_id", ) assert_matches_type(Plan, external_plan_id, path=["response"]) @parametrize async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> None: external_plan_id = await async_client.plans.external_plan_id.update( - "string", - external_plan_id="string", + other_external_plan_id="external_plan_id", + description="description", + external_plan_id="external_plan_id", metadata={"foo": "string"}, ) assert_matches_type(Plan, external_plan_id, path=["response"]) @@ -128,7 +131,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> No @parametrize async def test_raw_response_update(self, async_client: AsyncOrb) -> None: response = await async_client.plans.external_plan_id.with_raw_response.update( - "string", + other_external_plan_id="external_plan_id", ) assert response.is_closed is True @@ -139,7 +142,7 @@ async def test_raw_response_update(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: async with async_client.plans.external_plan_id.with_streaming_response.update( - "string", + other_external_plan_id="external_plan_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -155,21 +158,20 @@ async def test_path_params_update(self, async_client: AsyncOrb) -> None: ValueError, match=r"Expected a non-empty value for `other_external_plan_id` but received ''" ): await async_client.plans.external_plan_id.with_raw_response.update( - "", - external_plan_id="", + other_external_plan_id="", ) @parametrize async def test_method_fetch(self, async_client: AsyncOrb) -> None: external_plan_id = await async_client.plans.external_plan_id.fetch( - "string", + "external_plan_id", ) assert_matches_type(Plan, external_plan_id, path=["response"]) @parametrize async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: response = await async_client.plans.external_plan_id.with_raw_response.fetch( - "string", + "external_plan_id", ) assert response.is_closed is True @@ -180,7 +182,7 @@ async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_fetch(self, async_client: AsyncOrb) -> None: async with async_client.plans.external_plan_id.with_streaming_response.fetch( - "string", + "external_plan_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/plans/test_migrations.py b/tests/api_resources/plans/test_migrations.py new file mode 100644 index 00000000..d680314d --- /dev/null +++ b/tests/api_resources/plans/test_migrations.py @@ -0,0 +1,315 @@ +# 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 tests.utils import assert_matches_type +from orb.pagination import SyncPage, AsyncPage +from orb.types.plans import ( + MigrationListResponse, + MigrationCancelResponse, + MigrationRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMigrations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: Orb) -> None: + migration = client.plans.migrations.retrieve( + migration_id="migration_id", + plan_id="plan_id", + ) + assert_matches_type(MigrationRetrieveResponse, migration, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: Orb) -> None: + response = client.plans.migrations.with_raw_response.retrieve( + migration_id="migration_id", + plan_id="plan_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + migration = response.parse() + assert_matches_type(MigrationRetrieveResponse, migration, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: Orb) -> None: + with client.plans.migrations.with_streaming_response.retrieve( + migration_id="migration_id", + plan_id="plan_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + migration = response.parse() + assert_matches_type(MigrationRetrieveResponse, migration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): + client.plans.migrations.with_raw_response.retrieve( + migration_id="migration_id", + plan_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `migration_id` but received ''"): + client.plans.migrations.with_raw_response.retrieve( + migration_id="", + plan_id="plan_id", + ) + + @parametrize + def test_method_list(self, client: Orb) -> None: + migration = client.plans.migrations.list( + plan_id="plan_id", + ) + assert_matches_type(SyncPage[MigrationListResponse], migration, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Orb) -> None: + migration = client.plans.migrations.list( + plan_id="plan_id", + cursor="cursor", + limit=1, + ) + assert_matches_type(SyncPage[MigrationListResponse], migration, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Orb) -> None: + response = client.plans.migrations.with_raw_response.list( + plan_id="plan_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + migration = response.parse() + assert_matches_type(SyncPage[MigrationListResponse], migration, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Orb) -> None: + with client.plans.migrations.with_streaming_response.list( + plan_id="plan_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + migration = response.parse() + assert_matches_type(SyncPage[MigrationListResponse], migration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): + client.plans.migrations.with_raw_response.list( + plan_id="", + ) + + @parametrize + def test_method_cancel(self, client: Orb) -> None: + migration = client.plans.migrations.cancel( + migration_id="migration_id", + plan_id="plan_id", + ) + assert_matches_type(MigrationCancelResponse, migration, path=["response"]) + + @parametrize + def test_raw_response_cancel(self, client: Orb) -> None: + response = client.plans.migrations.with_raw_response.cancel( + migration_id="migration_id", + plan_id="plan_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + migration = response.parse() + assert_matches_type(MigrationCancelResponse, migration, path=["response"]) + + @parametrize + def test_streaming_response_cancel(self, client: Orb) -> None: + with client.plans.migrations.with_streaming_response.cancel( + migration_id="migration_id", + plan_id="plan_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + migration = response.parse() + assert_matches_type(MigrationCancelResponse, migration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_cancel(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): + client.plans.migrations.with_raw_response.cancel( + migration_id="migration_id", + plan_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `migration_id` but received ''"): + client.plans.migrations.with_raw_response.cancel( + migration_id="", + plan_id="plan_id", + ) + + +class TestAsyncMigrations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOrb) -> None: + migration = await async_client.plans.migrations.retrieve( + migration_id="migration_id", + plan_id="plan_id", + ) + assert_matches_type(MigrationRetrieveResponse, migration, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOrb) -> None: + response = await async_client.plans.migrations.with_raw_response.retrieve( + migration_id="migration_id", + plan_id="plan_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + migration = response.parse() + assert_matches_type(MigrationRetrieveResponse, migration, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOrb) -> None: + async with async_client.plans.migrations.with_streaming_response.retrieve( + migration_id="migration_id", + plan_id="plan_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + migration = await response.parse() + assert_matches_type(MigrationRetrieveResponse, migration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): + await async_client.plans.migrations.with_raw_response.retrieve( + migration_id="migration_id", + plan_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `migration_id` but received ''"): + await async_client.plans.migrations.with_raw_response.retrieve( + migration_id="", + plan_id="plan_id", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOrb) -> None: + migration = await async_client.plans.migrations.list( + plan_id="plan_id", + ) + assert_matches_type(AsyncPage[MigrationListResponse], migration, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: + migration = await async_client.plans.migrations.list( + plan_id="plan_id", + cursor="cursor", + limit=1, + ) + assert_matches_type(AsyncPage[MigrationListResponse], migration, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOrb) -> None: + response = await async_client.plans.migrations.with_raw_response.list( + plan_id="plan_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + migration = response.parse() + assert_matches_type(AsyncPage[MigrationListResponse], migration, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: + async with async_client.plans.migrations.with_streaming_response.list( + plan_id="plan_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + migration = await response.parse() + assert_matches_type(AsyncPage[MigrationListResponse], migration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): + await async_client.plans.migrations.with_raw_response.list( + plan_id="", + ) + + @parametrize + async def test_method_cancel(self, async_client: AsyncOrb) -> None: + migration = await async_client.plans.migrations.cancel( + migration_id="migration_id", + plan_id="plan_id", + ) + assert_matches_type(MigrationCancelResponse, migration, path=["response"]) + + @parametrize + async def test_raw_response_cancel(self, async_client: AsyncOrb) -> None: + response = await async_client.plans.migrations.with_raw_response.cancel( + migration_id="migration_id", + plan_id="plan_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + migration = response.parse() + assert_matches_type(MigrationCancelResponse, migration, path=["response"]) + + @parametrize + async def test_streaming_response_cancel(self, async_client: AsyncOrb) -> None: + async with async_client.plans.migrations.with_streaming_response.cancel( + migration_id="migration_id", + plan_id="plan_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + migration = await response.parse() + assert_matches_type(MigrationCancelResponse, migration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_cancel(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): + await async_client.plans.migrations.with_raw_response.cancel( + migration_id="migration_id", + plan_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `migration_id` but received ''"): + await async_client.plans.migrations.with_raw_response.cancel( + migration_id="", + plan_id="plan_id", + ) diff --git a/tests/api_resources/prices/test_external_price_id.py b/tests/api_resources/prices/test_external_price_id.py index abd884c2..1c995858 100644 --- a/tests/api_resources/prices/test_external_price_id.py +++ b/tests/api_resources/prices/test_external_price_id.py @@ -8,8 +8,8 @@ import pytest from orb import Orb, AsyncOrb -from orb.types import Price from tests.utils import assert_matches_type +from orb.types.shared import Price base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -17,17 +17,63 @@ class TestExternalPriceID: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + @parametrize + def test_method_update(self, client: Orb) -> None: + external_price_id = client.prices.external_price_id.update( + external_price_id="external_price_id", + ) + assert_matches_type(Price, external_price_id, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Orb) -> None: + external_price_id = client.prices.external_price_id.update( + external_price_id="external_price_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, external_price_id, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Orb) -> None: + response = client.prices.external_price_id.with_raw_response.update( + external_price_id="external_price_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_price_id = response.parse() + assert_matches_type(Price, external_price_id, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Orb) -> None: + with client.prices.external_price_id.with_streaming_response.update( + external_price_id="external_price_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_price_id = response.parse() + assert_matches_type(Price, external_price_id, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_price_id` but received ''"): + client.prices.external_price_id.with_raw_response.update( + external_price_id="", + ) + @parametrize def test_method_fetch(self, client: Orb) -> None: external_price_id = client.prices.external_price_id.fetch( - "string", + "external_price_id", ) assert_matches_type(Price, external_price_id, path=["response"]) @parametrize def test_raw_response_fetch(self, client: Orb) -> None: response = client.prices.external_price_id.with_raw_response.fetch( - "string", + "external_price_id", ) assert response.is_closed is True @@ -38,7 +84,7 @@ def test_raw_response_fetch(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch(self, client: Orb) -> None: with client.prices.external_price_id.with_streaming_response.fetch( - "string", + "external_price_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -57,19 +103,67 @@ def test_path_params_fetch(self, client: Orb) -> None: class TestAsyncExternalPriceID: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOrb) -> None: + external_price_id = await async_client.prices.external_price_id.update( + external_price_id="external_price_id", + ) + assert_matches_type(Price, external_price_id, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> None: + external_price_id = await async_client.prices.external_price_id.update( + external_price_id="external_price_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, external_price_id, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.external_price_id.with_raw_response.update( + external_price_id="external_price_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_price_id = response.parse() + assert_matches_type(Price, external_price_id, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: + async with async_client.prices.external_price_id.with_streaming_response.update( + external_price_id="external_price_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_price_id = await response.parse() + assert_matches_type(Price, external_price_id, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_price_id` but received ''"): + await async_client.prices.external_price_id.with_raw_response.update( + external_price_id="", + ) @parametrize async def test_method_fetch(self, async_client: AsyncOrb) -> None: external_price_id = await async_client.prices.external_price_id.fetch( - "string", + "external_price_id", ) assert_matches_type(Price, external_price_id, path=["response"]) @parametrize async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: response = await async_client.prices.external_price_id.with_raw_response.fetch( - "string", + "external_price_id", ) assert response.is_closed is True @@ -80,7 +174,7 @@ async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_fetch(self, async_client: AsyncOrb) -> None: async with async_client.prices.external_price_id.with_streaming_response.fetch( - "string", + "external_price_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/test_alerts.py b/tests/api_resources/test_alerts.py new file mode 100644 index 00000000..f369415a --- /dev/null +++ b/tests/api_resources/test_alerts.py @@ -0,0 +1,880 @@ +# 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.types import ( + Alert, +) +from orb._utils import parse_datetime +from tests.utils import assert_matches_type +from orb.pagination import SyncPage, AsyncPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAlerts: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: Orb) -> None: + alert = client.alerts.retrieve( + "alert_id", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: Orb) -> None: + response = client.alerts.with_raw_response.retrieve( + "alert_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: Orb) -> None: + with client.alerts.with_streaming_response.retrieve( + "alert_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `alert_id` but received ''"): + client.alerts.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: Orb) -> None: + alert = client.alerts.update( + alert_configuration_id="alert_configuration_id", + thresholds=[{"value": 0}], + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Orb) -> None: + alert = client.alerts.update( + alert_configuration_id="alert_configuration_id", + thresholds=[{"value": 0}], + price_filters=[ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + threshold_overrides=[ + { + "group_values": ["string"], + "thresholds": [{"value": 0}], + } + ], + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + 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}], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + 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}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Orb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `alert_configuration_id` but received ''" + ): + client.alerts.with_raw_response.update( + alert_configuration_id="", + thresholds=[{"value": 0}], + ) + + @pytest.mark.skip(reason="plan_version=0 breaks Prism") + @parametrize + def test_method_list(self, client: Orb) -> None: + alert = client.alerts.list() + assert_matches_type(SyncPage[Alert], alert, path=["response"]) + + @pytest.mark.skip(reason="plan_version=0 breaks Prism") + @parametrize + def test_method_list_with_all_params(self, client: Orb) -> None: + alert = client.alerts.list( + created_at_gt=parse_datetime("2019-12-27T18:11:19.117Z"), + created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), + 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="customer_id", + external_customer_id="external_customer_id", + limit=1, + subscription_id="subscription_id", + ) + assert_matches_type(SyncPage[Alert], alert, path=["response"]) + + @pytest.mark.skip(reason="plan_version=0 breaks Prism") + @parametrize + def test_raw_response_list(self, client: Orb) -> None: + response = client.alerts.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(SyncPage[Alert], alert, path=["response"]) + + @pytest.mark.skip(reason="plan_version=0 breaks Prism") + @parametrize + def test_streaming_response_list(self, client: Orb) -> None: + with client.alerts.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = response.parse() + assert_matches_type(SyncPage[Alert], alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_for_customer(self, client: Orb) -> None: + alert = client.alerts.create_for_customer( + customer_id="customer_id", + currency="currency", + type="credit_balance_depleted", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_method_create_for_customer_with_all_params(self, client: Orb) -> None: + alert = client.alerts.create_for_customer( + customer_id="customer_id", + currency="currency", + type="credit_balance_depleted", + thresholds=[{"value": 0}], + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_raw_response_create_for_customer(self, client: Orb) -> None: + response = client.alerts.with_raw_response.create_for_customer( + customer_id="customer_id", + currency="currency", + type="credit_balance_depleted", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_streaming_response_create_for_customer(self, client: Orb) -> None: + with client.alerts.with_streaming_response.create_for_customer( + customer_id="customer_id", + currency="currency", + type="credit_balance_depleted", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create_for_customer(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): + client.alerts.with_raw_response.create_for_customer( + customer_id="", + currency="currency", + type="credit_balance_depleted", + ) + + @parametrize + def test_method_create_for_external_customer(self, client: Orb) -> None: + alert = client.alerts.create_for_external_customer( + external_customer_id="external_customer_id", + currency="currency", + type="credit_balance_depleted", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_method_create_for_external_customer_with_all_params(self, client: Orb) -> None: + alert = client.alerts.create_for_external_customer( + external_customer_id="external_customer_id", + currency="currency", + type="credit_balance_depleted", + thresholds=[{"value": 0}], + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_raw_response_create_for_external_customer(self, client: Orb) -> None: + response = client.alerts.with_raw_response.create_for_external_customer( + external_customer_id="external_customer_id", + currency="currency", + type="credit_balance_depleted", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_streaming_response_create_for_external_customer(self, client: Orb) -> None: + with client.alerts.with_streaming_response.create_for_external_customer( + external_customer_id="external_customer_id", + currency="currency", + type="credit_balance_depleted", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create_for_external_customer(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): + client.alerts.with_raw_response.create_for_external_customer( + external_customer_id="", + currency="currency", + type="credit_balance_depleted", + ) + + @parametrize + def test_method_create_for_subscription(self, client: Orb) -> None: + alert = client.alerts.create_for_subscription( + subscription_id="subscription_id", + thresholds=[{"value": 0}], + type="usage_exceeded", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + 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}], + type="usage_exceeded", + currency="currency", + grouping_keys=["string"], + metric_id="metric_id", + price_filters=[ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + threshold_overrides=[ + { + "group_values": ["string"], + "thresholds": [{"value": 0}], + } + ], + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + 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}], + type="usage_exceeded", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + 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}], + type="usage_exceeded", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + 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}], + type="usage_exceeded", + ) + + @parametrize + def test_method_disable(self, client: Orb) -> None: + alert = client.alerts.disable( + alert_configuration_id="alert_configuration_id", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_method_disable_with_all_params(self, client: Orb) -> None: + alert = client.alerts.disable( + alert_configuration_id="alert_configuration_id", + subscription_id="subscription_id", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_raw_response_disable(self, client: Orb) -> None: + response = client.alerts.with_raw_response.disable( + alert_configuration_id="alert_configuration_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_streaming_response_disable(self, client: Orb) -> None: + with client.alerts.with_streaming_response.disable( + alert_configuration_id="alert_configuration_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_disable(self, client: Orb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `alert_configuration_id` but received ''" + ): + client.alerts.with_raw_response.disable( + alert_configuration_id="", + ) + + @parametrize + def test_method_enable(self, client: Orb) -> None: + alert = client.alerts.enable( + alert_configuration_id="alert_configuration_id", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_method_enable_with_all_params(self, client: Orb) -> None: + alert = client.alerts.enable( + alert_configuration_id="alert_configuration_id", + subscription_id="subscription_id", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_raw_response_enable(self, client: Orb) -> None: + response = client.alerts.with_raw_response.enable( + alert_configuration_id="alert_configuration_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + def test_streaming_response_enable(self, client: Orb) -> None: + with client.alerts.with_streaming_response.enable( + alert_configuration_id="alert_configuration_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_enable(self, client: Orb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `alert_configuration_id` but received ''" + ): + client.alerts.with_raw_response.enable( + alert_configuration_id="", + ) + + +class TestAsyncAlerts: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOrb) -> None: + alert = await async_client.alerts.retrieve( + "alert_id", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOrb) -> None: + response = await async_client.alerts.with_raw_response.retrieve( + "alert_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOrb) -> None: + async with async_client.alerts.with_streaming_response.retrieve( + "alert_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = await response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `alert_id` but received ''"): + await async_client.alerts.with_raw_response.retrieve( + "", + ) + + @parametrize + 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}], + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> None: + alert = await async_client.alerts.update( + alert_configuration_id="alert_configuration_id", + thresholds=[{"value": 0}], + price_filters=[ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + threshold_overrides=[ + { + "group_values": ["string"], + "thresholds": [{"value": 0}], + } + ], + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + 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}], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + 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}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = await response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOrb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `alert_configuration_id` but received ''" + ): + await async_client.alerts.with_raw_response.update( + alert_configuration_id="", + thresholds=[{"value": 0}], + ) + + @pytest.mark.skip(reason="plan_version=0 breaks Prism") + @parametrize + async def test_method_list(self, async_client: AsyncOrb) -> None: + alert = await async_client.alerts.list() + assert_matches_type(AsyncPage[Alert], alert, path=["response"]) + + @pytest.mark.skip(reason="plan_version=0 breaks Prism") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: + alert = await async_client.alerts.list( + created_at_gt=parse_datetime("2019-12-27T18:11:19.117Z"), + created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), + 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="customer_id", + external_customer_id="external_customer_id", + limit=1, + subscription_id="subscription_id", + ) + assert_matches_type(AsyncPage[Alert], alert, path=["response"]) + + @pytest.mark.skip(reason="plan_version=0 breaks Prism") + @parametrize + async def test_raw_response_list(self, async_client: AsyncOrb) -> None: + response = await async_client.alerts.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(AsyncPage[Alert], alert, path=["response"]) + + @pytest.mark.skip(reason="plan_version=0 breaks Prism") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: + async with async_client.alerts.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = await response.parse() + assert_matches_type(AsyncPage[Alert], alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_for_customer(self, async_client: AsyncOrb) -> None: + alert = await async_client.alerts.create_for_customer( + customer_id="customer_id", + currency="currency", + type="credit_balance_depleted", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_method_create_for_customer_with_all_params(self, async_client: AsyncOrb) -> None: + alert = await async_client.alerts.create_for_customer( + customer_id="customer_id", + currency="currency", + type="credit_balance_depleted", + thresholds=[{"value": 0}], + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_raw_response_create_for_customer(self, async_client: AsyncOrb) -> None: + response = await async_client.alerts.with_raw_response.create_for_customer( + customer_id="customer_id", + currency="currency", + type="credit_balance_depleted", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_streaming_response_create_for_customer(self, async_client: AsyncOrb) -> None: + async with async_client.alerts.with_streaming_response.create_for_customer( + customer_id="customer_id", + currency="currency", + type="credit_balance_depleted", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = await response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create_for_customer(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): + await async_client.alerts.with_raw_response.create_for_customer( + customer_id="", + currency="currency", + type="credit_balance_depleted", + ) + + @parametrize + async def test_method_create_for_external_customer(self, async_client: AsyncOrb) -> None: + alert = await async_client.alerts.create_for_external_customer( + external_customer_id="external_customer_id", + currency="currency", + type="credit_balance_depleted", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_method_create_for_external_customer_with_all_params(self, async_client: AsyncOrb) -> None: + alert = await async_client.alerts.create_for_external_customer( + external_customer_id="external_customer_id", + currency="currency", + type="credit_balance_depleted", + thresholds=[{"value": 0}], + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_raw_response_create_for_external_customer(self, async_client: AsyncOrb) -> None: + response = await async_client.alerts.with_raw_response.create_for_external_customer( + external_customer_id="external_customer_id", + currency="currency", + type="credit_balance_depleted", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_streaming_response_create_for_external_customer(self, async_client: AsyncOrb) -> None: + async with async_client.alerts.with_streaming_response.create_for_external_customer( + external_customer_id="external_customer_id", + currency="currency", + type="credit_balance_depleted", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = await response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create_for_external_customer(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): + await async_client.alerts.with_raw_response.create_for_external_customer( + external_customer_id="", + currency="currency", + type="credit_balance_depleted", + ) + + @parametrize + 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}], + type="usage_exceeded", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + 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}], + type="usage_exceeded", + currency="currency", + grouping_keys=["string"], + metric_id="metric_id", + price_filters=[ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + threshold_overrides=[ + { + "group_values": ["string"], + "thresholds": [{"value": 0}], + } + ], + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + 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}], + type="usage_exceeded", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + 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}], + type="usage_exceeded", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = await response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create_for_subscription(self, async_client: AsyncOrb) -> None: + 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}], + type="usage_exceeded", + ) + + @parametrize + async def test_method_disable(self, async_client: AsyncOrb) -> None: + alert = await async_client.alerts.disable( + alert_configuration_id="alert_configuration_id", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_method_disable_with_all_params(self, async_client: AsyncOrb) -> None: + alert = await async_client.alerts.disable( + alert_configuration_id="alert_configuration_id", + subscription_id="subscription_id", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_raw_response_disable(self, async_client: AsyncOrb) -> None: + response = await async_client.alerts.with_raw_response.disable( + alert_configuration_id="alert_configuration_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_streaming_response_disable(self, async_client: AsyncOrb) -> None: + async with async_client.alerts.with_streaming_response.disable( + alert_configuration_id="alert_configuration_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = await response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_disable(self, async_client: AsyncOrb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `alert_configuration_id` but received ''" + ): + await async_client.alerts.with_raw_response.disable( + alert_configuration_id="", + ) + + @parametrize + async def test_method_enable(self, async_client: AsyncOrb) -> None: + alert = await async_client.alerts.enable( + alert_configuration_id="alert_configuration_id", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_method_enable_with_all_params(self, async_client: AsyncOrb) -> None: + alert = await async_client.alerts.enable( + alert_configuration_id="alert_configuration_id", + subscription_id="subscription_id", + ) + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_raw_response_enable(self, async_client: AsyncOrb) -> None: + response = await async_client.alerts.with_raw_response.enable( + alert_configuration_id="alert_configuration_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + alert = response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + @parametrize + async def test_streaming_response_enable(self, async_client: AsyncOrb) -> None: + async with async_client.alerts.with_streaming_response.enable( + alert_configuration_id="alert_configuration_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + alert = await response.parse() + assert_matches_type(Alert, alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_enable(self, async_client: AsyncOrb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `alert_configuration_id` but received ''" + ): + await async_client.alerts.with_raw_response.enable( + alert_configuration_id="", + ) diff --git a/tests/api_resources/test_beta.py b/tests/api_resources/test_beta.py new file mode 100644 index 00000000..d2f31794 --- /dev/null +++ b/tests/api_resources/test_beta.py @@ -0,0 +1,850 @@ +# 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.types import Plan, PlanVersion +from tests.utils import assert_matches_type + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestBeta: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create_plan_version(self, client: Orb) -> None: + beta = client.beta.create_plan_version( + plan_id="plan_id", + version=0, + ) + assert_matches_type(PlanVersion, beta, path=["response"]) + + @parametrize + def test_method_create_plan_version_with_all_params(self, client: Orb) -> None: + beta = client.beta.create_plan_version( + plan_id="plan_id", + version=0, + add_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "plan_phase_order": 0, + } + ], + add_prices=[ + { + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "license_allocation_price": { + "cadence": "annual", + "item_id": "item_id", + "license_allocations": [ + { + "amount": "amount", + "currency": "currency", + "write_off_overage": True, + } + ], + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "plan_phase_order": 0, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + } + ], + remove_adjustments=[ + { + "adjustment_id": "adjustment_id", + "plan_phase_order": 0, + } + ], + remove_prices=[ + { + "price_id": "price_id", + "plan_phase_order": 0, + } + ], + replace_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "replaces_adjustment_id": "replaces_adjustment_id", + "plan_phase_order": 0, + } + ], + replace_prices=[ + { + "replaces_price_id": "replaces_price_id", + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "license_allocation_price": { + "cadence": "annual", + "item_id": "item_id", + "license_allocations": [ + { + "amount": "amount", + "currency": "currency", + "write_off_overage": True, + } + ], + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "plan_phase_order": 0, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + } + ], + set_as_default=True, + ) + assert_matches_type(PlanVersion, beta, path=["response"]) + + @parametrize + def test_raw_response_create_plan_version(self, client: Orb) -> None: + response = client.beta.with_raw_response.create_plan_version( + plan_id="plan_id", + version=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + beta = response.parse() + assert_matches_type(PlanVersion, beta, path=["response"]) + + @parametrize + def test_streaming_response_create_plan_version(self, client: Orb) -> None: + with client.beta.with_streaming_response.create_plan_version( + plan_id="plan_id", + version=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + beta = response.parse() + assert_matches_type(PlanVersion, beta, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create_plan_version(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): + client.beta.with_raw_response.create_plan_version( + plan_id="", + version=0, + ) + + @parametrize + def test_method_fetch_plan_version(self, client: Orb) -> None: + beta = client.beta.fetch_plan_version( + version="version", + plan_id="plan_id", + ) + assert_matches_type(PlanVersion, beta, path=["response"]) + + @parametrize + def test_raw_response_fetch_plan_version(self, client: Orb) -> None: + response = client.beta.with_raw_response.fetch_plan_version( + version="version", + plan_id="plan_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + beta = response.parse() + assert_matches_type(PlanVersion, beta, path=["response"]) + + @parametrize + def test_streaming_response_fetch_plan_version(self, client: Orb) -> None: + with client.beta.with_streaming_response.fetch_plan_version( + version="version", + plan_id="plan_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + beta = response.parse() + assert_matches_type(PlanVersion, beta, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_fetch_plan_version(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): + client.beta.with_raw_response.fetch_plan_version( + version="version", + plan_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `version` but received ''"): + client.beta.with_raw_response.fetch_plan_version( + version="", + plan_id="plan_id", + ) + + @parametrize + def test_method_set_default_plan_version(self, client: Orb) -> None: + beta = client.beta.set_default_plan_version( + plan_id="plan_id", + version=0, + ) + assert_matches_type(Plan, beta, path=["response"]) + + @parametrize + def test_raw_response_set_default_plan_version(self, client: Orb) -> None: + response = client.beta.with_raw_response.set_default_plan_version( + plan_id="plan_id", + version=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + beta = response.parse() + assert_matches_type(Plan, beta, path=["response"]) + + @parametrize + def test_streaming_response_set_default_plan_version(self, client: Orb) -> None: + with client.beta.with_streaming_response.set_default_plan_version( + plan_id="plan_id", + version=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + beta = response.parse() + assert_matches_type(Plan, beta, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_set_default_plan_version(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): + client.beta.with_raw_response.set_default_plan_version( + plan_id="", + version=0, + ) + + +class TestAsyncBeta: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create_plan_version(self, async_client: AsyncOrb) -> None: + beta = await async_client.beta.create_plan_version( + plan_id="plan_id", + version=0, + ) + assert_matches_type(PlanVersion, beta, path=["response"]) + + @parametrize + async def test_method_create_plan_version_with_all_params(self, async_client: AsyncOrb) -> None: + beta = await async_client.beta.create_plan_version( + plan_id="plan_id", + version=0, + add_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "plan_phase_order": 0, + } + ], + add_prices=[ + { + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "license_allocation_price": { + "cadence": "annual", + "item_id": "item_id", + "license_allocations": [ + { + "amount": "amount", + "currency": "currency", + "write_off_overage": True, + } + ], + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "plan_phase_order": 0, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + } + ], + remove_adjustments=[ + { + "adjustment_id": "adjustment_id", + "plan_phase_order": 0, + } + ], + remove_prices=[ + { + "price_id": "price_id", + "plan_phase_order": 0, + } + ], + replace_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "replaces_adjustment_id": "replaces_adjustment_id", + "plan_phase_order": 0, + } + ], + replace_prices=[ + { + "replaces_price_id": "replaces_price_id", + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "license_allocation_price": { + "cadence": "annual", + "item_id": "item_id", + "license_allocations": [ + { + "amount": "amount", + "currency": "currency", + "write_off_overage": True, + } + ], + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "plan_phase_order": 0, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + } + ], + set_as_default=True, + ) + assert_matches_type(PlanVersion, beta, path=["response"]) + + @parametrize + async def test_raw_response_create_plan_version(self, async_client: AsyncOrb) -> None: + response = await async_client.beta.with_raw_response.create_plan_version( + plan_id="plan_id", + version=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + beta = response.parse() + assert_matches_type(PlanVersion, beta, path=["response"]) + + @parametrize + async def test_streaming_response_create_plan_version(self, async_client: AsyncOrb) -> None: + async with async_client.beta.with_streaming_response.create_plan_version( + plan_id="plan_id", + version=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + beta = await response.parse() + assert_matches_type(PlanVersion, beta, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create_plan_version(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): + await async_client.beta.with_raw_response.create_plan_version( + plan_id="", + version=0, + ) + + @parametrize + async def test_method_fetch_plan_version(self, async_client: AsyncOrb) -> None: + beta = await async_client.beta.fetch_plan_version( + version="version", + plan_id="plan_id", + ) + assert_matches_type(PlanVersion, beta, path=["response"]) + + @parametrize + async def test_raw_response_fetch_plan_version(self, async_client: AsyncOrb) -> None: + response = await async_client.beta.with_raw_response.fetch_plan_version( + version="version", + plan_id="plan_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + beta = response.parse() + assert_matches_type(PlanVersion, beta, path=["response"]) + + @parametrize + async def test_streaming_response_fetch_plan_version(self, async_client: AsyncOrb) -> None: + async with async_client.beta.with_streaming_response.fetch_plan_version( + version="version", + plan_id="plan_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + beta = await response.parse() + assert_matches_type(PlanVersion, beta, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_fetch_plan_version(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): + await async_client.beta.with_raw_response.fetch_plan_version( + version="version", + plan_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `version` but received ''"): + await async_client.beta.with_raw_response.fetch_plan_version( + version="", + plan_id="plan_id", + ) + + @parametrize + async def test_method_set_default_plan_version(self, async_client: AsyncOrb) -> None: + beta = await async_client.beta.set_default_plan_version( + plan_id="plan_id", + version=0, + ) + assert_matches_type(Plan, beta, path=["response"]) + + @parametrize + async def test_raw_response_set_default_plan_version(self, async_client: AsyncOrb) -> None: + response = await async_client.beta.with_raw_response.set_default_plan_version( + plan_id="plan_id", + version=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + beta = response.parse() + assert_matches_type(Plan, beta, path=["response"]) + + @parametrize + async def test_streaming_response_set_default_plan_version(self, async_client: AsyncOrb) -> None: + async with async_client.beta.with_streaming_response.set_default_plan_version( + plan_id="plan_id", + version=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + beta = await response.parse() + assert_matches_type(Plan, beta, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_set_default_plan_version(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): + await async_client.beta.with_raw_response.set_default_plan_version( + plan_id="", + version=0, + ) diff --git a/tests/api_resources/test_coupons.py b/tests/api_resources/test_coupons.py index fdf87fdb..7b888a5e 100644 --- a/tests/api_resources/test_coupons.py +++ b/tests/api_resources/test_coupons.py @@ -23,8 +23,7 @@ def test_method_create(self, client: Orb) -> None: coupon = client.coupons.create( discount={ "discount_type": "percentage", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, + "percentage_discount": 0, }, redemption_code="HALFOFF", ) @@ -35,13 +34,11 @@ def test_method_create_with_all_params(self, client: Orb) -> None: coupon = client.coupons.create( discount={ "discount_type": "percentage", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "reason": "string", - "percentage_discount": 0.15, + "percentage_discount": 0, }, redemption_code="HALFOFF", duration_in_months=12, - max_redemptions=0, + max_redemptions=1, ) assert_matches_type(Coupon, coupon, path=["response"]) @@ -50,8 +47,7 @@ def test_raw_response_create(self, client: Orb) -> None: response = client.coupons.with_raw_response.create( discount={ "discount_type": "percentage", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, + "percentage_discount": 0, }, redemption_code="HALFOFF", ) @@ -66,8 +62,7 @@ def test_streaming_response_create(self, client: Orb) -> None: with client.coupons.with_streaming_response.create( discount={ "discount_type": "percentage", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, + "percentage_discount": 0, }, redemption_code="HALFOFF", ) as response: @@ -87,9 +82,9 @@ def test_method_list(self, client: Orb) -> None: @parametrize def test_method_list_with_all_params(self, client: Orb) -> None: coupon = client.coupons.list( - cursor="string", - limit=0, - redemption_code="string", + cursor="cursor", + limit=1, + redemption_code="redemption_code", show_archived=True, ) assert_matches_type(SyncPage[Coupon], coupon, path=["response"]) @@ -117,14 +112,14 @@ def test_streaming_response_list(self, client: Orb) -> None: @parametrize def test_method_archive(self, client: Orb) -> None: coupon = client.coupons.archive( - "string", + "coupon_id", ) assert_matches_type(Coupon, coupon, path=["response"]) @parametrize def test_raw_response_archive(self, client: Orb) -> None: response = client.coupons.with_raw_response.archive( - "string", + "coupon_id", ) assert response.is_closed is True @@ -135,7 +130,7 @@ def test_raw_response_archive(self, client: Orb) -> None: @parametrize def test_streaming_response_archive(self, client: Orb) -> None: with client.coupons.with_streaming_response.archive( - "string", + "coupon_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -155,14 +150,14 @@ def test_path_params_archive(self, client: Orb) -> None: @parametrize def test_method_fetch(self, client: Orb) -> None: coupon = client.coupons.fetch( - "string", + "coupon_id", ) assert_matches_type(Coupon, coupon, path=["response"]) @parametrize def test_raw_response_fetch(self, client: Orb) -> None: response = client.coupons.with_raw_response.fetch( - "string", + "coupon_id", ) assert response.is_closed is True @@ -173,7 +168,7 @@ def test_raw_response_fetch(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch(self, client: Orb) -> None: with client.coupons.with_streaming_response.fetch( - "string", + "coupon_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -192,15 +187,16 @@ def test_path_params_fetch(self, client: Orb) -> None: class TestAsyncCoupons: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOrb) -> None: coupon = await async_client.coupons.create( discount={ "discount_type": "percentage", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, + "percentage_discount": 0, }, redemption_code="HALFOFF", ) @@ -211,13 +207,11 @@ async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> No coupon = await async_client.coupons.create( discount={ "discount_type": "percentage", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "reason": "string", - "percentage_discount": 0.15, + "percentage_discount": 0, }, redemption_code="HALFOFF", duration_in_months=12, - max_redemptions=0, + max_redemptions=1, ) assert_matches_type(Coupon, coupon, path=["response"]) @@ -226,8 +220,7 @@ async def test_raw_response_create(self, async_client: AsyncOrb) -> None: response = await async_client.coupons.with_raw_response.create( discount={ "discount_type": "percentage", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, + "percentage_discount": 0, }, redemption_code="HALFOFF", ) @@ -242,8 +235,7 @@ async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: async with async_client.coupons.with_streaming_response.create( discount={ "discount_type": "percentage", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, + "percentage_discount": 0, }, redemption_code="HALFOFF", ) as response: @@ -263,9 +255,9 @@ async def test_method_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: coupon = await async_client.coupons.list( - cursor="string", - limit=0, - redemption_code="string", + cursor="cursor", + limit=1, + redemption_code="redemption_code", show_archived=True, ) assert_matches_type(AsyncPage[Coupon], coupon, path=["response"]) @@ -293,14 +285,14 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_archive(self, async_client: AsyncOrb) -> None: coupon = await async_client.coupons.archive( - "string", + "coupon_id", ) assert_matches_type(Coupon, coupon, path=["response"]) @parametrize async def test_raw_response_archive(self, async_client: AsyncOrb) -> None: response = await async_client.coupons.with_raw_response.archive( - "string", + "coupon_id", ) assert response.is_closed is True @@ -311,7 +303,7 @@ async def test_raw_response_archive(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_archive(self, async_client: AsyncOrb) -> None: async with async_client.coupons.with_streaming_response.archive( - "string", + "coupon_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -331,14 +323,14 @@ async def test_path_params_archive(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_fetch(self, async_client: AsyncOrb) -> None: coupon = await async_client.coupons.fetch( - "string", + "coupon_id", ) assert_matches_type(Coupon, coupon, path=["response"]) @parametrize async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: response = await async_client.coupons.with_raw_response.fetch( - "string", + "coupon_id", ) assert response.is_closed is True @@ -349,7 +341,7 @@ async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_fetch(self, async_client: AsyncOrb) -> None: async with async_client.coupons.with_streaming_response.fetch( - "string", + "coupon_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/test_credit_blocks.py b/tests/api_resources/test_credit_blocks.py new file mode 100644 index 00000000..e0409aac --- /dev/null +++ b/tests/api_resources/test_credit_blocks.py @@ -0,0 +1,252 @@ +# 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.types import CreditBlockRetrieveResponse, CreditBlockListInvoicesResponse +from tests.utils import assert_matches_type + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCreditBlocks: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: Orb) -> None: + credit_block = client.credit_blocks.retrieve( + "block_id", + ) + assert_matches_type(CreditBlockRetrieveResponse, credit_block, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: Orb) -> None: + response = client.credit_blocks.with_raw_response.retrieve( + "block_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + credit_block = response.parse() + assert_matches_type(CreditBlockRetrieveResponse, credit_block, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: Orb) -> None: + with client.credit_blocks.with_streaming_response.retrieve( + "block_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + credit_block = response.parse() + assert_matches_type(CreditBlockRetrieveResponse, credit_block, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `block_id` but received ''"): + client.credit_blocks.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_delete(self, client: Orb) -> None: + credit_block = client.credit_blocks.delete( + "block_id", + ) + assert credit_block is None + + @parametrize + def test_raw_response_delete(self, client: Orb) -> None: + response = client.credit_blocks.with_raw_response.delete( + "block_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + credit_block = response.parse() + assert credit_block is None + + @parametrize + def test_streaming_response_delete(self, client: Orb) -> None: + with client.credit_blocks.with_streaming_response.delete( + "block_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + credit_block = response.parse() + assert credit_block is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `block_id` but received ''"): + client.credit_blocks.with_raw_response.delete( + "", + ) + + @parametrize + def test_method_list_invoices(self, client: Orb) -> None: + credit_block = client.credit_blocks.list_invoices( + "block_id", + ) + assert_matches_type(CreditBlockListInvoicesResponse, credit_block, path=["response"]) + + @parametrize + def test_raw_response_list_invoices(self, client: Orb) -> None: + response = client.credit_blocks.with_raw_response.list_invoices( + "block_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + credit_block = response.parse() + assert_matches_type(CreditBlockListInvoicesResponse, credit_block, path=["response"]) + + @parametrize + def test_streaming_response_list_invoices(self, client: Orb) -> None: + with client.credit_blocks.with_streaming_response.list_invoices( + "block_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + credit_block = response.parse() + assert_matches_type(CreditBlockListInvoicesResponse, credit_block, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list_invoices(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `block_id` but received ''"): + client.credit_blocks.with_raw_response.list_invoices( + "", + ) + + +class TestAsyncCreditBlocks: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOrb) -> None: + credit_block = await async_client.credit_blocks.retrieve( + "block_id", + ) + assert_matches_type(CreditBlockRetrieveResponse, credit_block, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOrb) -> None: + response = await async_client.credit_blocks.with_raw_response.retrieve( + "block_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + credit_block = response.parse() + assert_matches_type(CreditBlockRetrieveResponse, credit_block, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOrb) -> None: + async with async_client.credit_blocks.with_streaming_response.retrieve( + "block_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + credit_block = await response.parse() + assert_matches_type(CreditBlockRetrieveResponse, credit_block, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `block_id` but received ''"): + await async_client.credit_blocks.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncOrb) -> None: + credit_block = await async_client.credit_blocks.delete( + "block_id", + ) + assert credit_block is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncOrb) -> None: + response = await async_client.credit_blocks.with_raw_response.delete( + "block_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + credit_block = response.parse() + assert credit_block is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOrb) -> None: + async with async_client.credit_blocks.with_streaming_response.delete( + "block_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + credit_block = await response.parse() + assert credit_block is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `block_id` but received ''"): + await async_client.credit_blocks.with_raw_response.delete( + "", + ) + + @parametrize + async def test_method_list_invoices(self, async_client: AsyncOrb) -> None: + credit_block = await async_client.credit_blocks.list_invoices( + "block_id", + ) + assert_matches_type(CreditBlockListInvoicesResponse, credit_block, path=["response"]) + + @parametrize + async def test_raw_response_list_invoices(self, async_client: AsyncOrb) -> None: + response = await async_client.credit_blocks.with_raw_response.list_invoices( + "block_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + credit_block = response.parse() + assert_matches_type(CreditBlockListInvoicesResponse, credit_block, path=["response"]) + + @parametrize + async def test_streaming_response_list_invoices(self, async_client: AsyncOrb) -> None: + async with async_client.credit_blocks.with_streaming_response.list_invoices( + "block_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + credit_block = await response.parse() + assert_matches_type(CreditBlockListInvoicesResponse, credit_block, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list_invoices(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `block_id` but received ''"): + await async_client.credit_blocks.with_raw_response.list_invoices( + "", + ) diff --git a/tests/api_resources/test_credit_notes.py b/tests/api_resources/test_credit_notes.py index 4857a639..01c84445 100644 --- a/tests/api_resources/test_credit_notes.py +++ b/tests/api_resources/test_credit_notes.py @@ -8,9 +8,10 @@ import pytest from orb import Orb, AsyncOrb -from orb.types import CreditNote +from orb._utils import parse_date, parse_datetime from tests.utils import assert_matches_type from orb.pagination import SyncPage, AsyncPage +from orb.types.shared import CreditNote base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -18,6 +19,73 @@ 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", + } + ], + reason="duplicate", + ) + 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", + "end_date": parse_date("2023-09-22"), + "start_date": parse_date("2023-09-22"), + } + ], + reason="duplicate", + end_date=parse_date("2023-09-22"), + memo="An optional memo for my credit note.", + start_date=parse_date("2023-09-22"), + ) + 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", + } + ], + reason="duplicate", + ) + + 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", + } + ], + reason="duplicate", + ) 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() @@ -26,8 +94,12 @@ def test_method_list(self, client: Orb) -> None: @parametrize def test_method_list_with_all_params(self, client: Orb) -> None: credit_note = client.credit_notes.list( - cursor="string", - limit=0, + created_at_gt=parse_datetime("2019-12-27T18:11:19.117Z"), + created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), + created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), + created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), + cursor="cursor", + limit=1, ) assert_matches_type(SyncPage[CreditNote], credit_note, path=["response"]) @@ -54,14 +126,14 @@ def test_streaming_response_list(self, client: Orb) -> None: @parametrize def test_method_fetch(self, client: Orb) -> None: credit_note = client.credit_notes.fetch( - "string", + "credit_note_id", ) assert_matches_type(CreditNote, credit_note, path=["response"]) @parametrize def test_raw_response_fetch(self, client: Orb) -> None: response = client.credit_notes.with_raw_response.fetch( - "string", + "credit_note_id", ) assert response.is_closed is True @@ -72,7 +144,7 @@ def test_raw_response_fetch(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch(self, client: Orb) -> None: with client.credit_notes.with_streaming_response.fetch( - "string", + "credit_note_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -91,7 +163,76 @@ 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 = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @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", + } + ], + reason="duplicate", + ) + 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", + "end_date": parse_date("2023-09-22"), + "start_date": parse_date("2023-09-22"), + } + ], + reason="duplicate", + end_date=parse_date("2023-09-22"), + memo="An optional memo for my credit note.", + start_date=parse_date("2023-09-22"), + ) + 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", + } + ], + reason="duplicate", + ) + + 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", + } + ], + reason="duplicate", + ) 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: @@ -101,8 +242,12 @@ async def test_method_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: credit_note = await async_client.credit_notes.list( - cursor="string", - limit=0, + created_at_gt=parse_datetime("2019-12-27T18:11:19.117Z"), + created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), + created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), + created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), + cursor="cursor", + limit=1, ) assert_matches_type(AsyncPage[CreditNote], credit_note, path=["response"]) @@ -129,14 +274,14 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_fetch(self, async_client: AsyncOrb) -> None: credit_note = await async_client.credit_notes.fetch( - "string", + "credit_note_id", ) assert_matches_type(CreditNote, credit_note, path=["response"]) @parametrize async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: response = await async_client.credit_notes.with_raw_response.fetch( - "string", + "credit_note_id", ) assert response.is_closed is True @@ -147,7 +292,7 @@ async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_fetch(self, async_client: AsyncOrb) -> None: async with async_client.credit_notes.with_streaming_response.fetch( - "string", + "credit_note_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/test_customers.py b/tests/api_resources/test_customers.py index d32ee21b..731b5caa 100644 --- a/tests/api_resources/test_customers.py +++ b/tests/api_resources/test_customers.py @@ -24,72 +24,84 @@ class TestCustomers: @parametrize def test_method_create(self, client: Orb) -> None: customer = client.customers.create( - email="string", - name="string", + email="dev@stainless.com", + name="x", ) assert_matches_type(Customer, customer, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: Orb) -> None: customer = client.customers.create( - email="string", - name="string", + email="dev@stainless.com", + name="x", accounting_sync_configuration={ - "excluded": True, "accounting_providers": [ { - "provider_type": "string", - "external_provider_id": "string", - }, - { - "provider_type": "string", - "external_provider_id": "string", - }, - { - "provider_type": "string", - "external_provider_id": "string", - }, + "external_provider_id": "external_provider_id", + "provider_type": "quickbooks", + } ], + "excluded": True, }, - additional_emails=["string", "string", "string"], + additional_emails=["dev@stainless.com"], auto_collection=True, + auto_issuance=True, billing_address={ - "line1": "string", - "line2": "string", - "city": "string", - "state": "string", - "postal_code": "string", - "country": "string", - }, - currency="string", + "city": "city", + "country": "country", + "line1": "line1", + "line2": "line2", + "postal_code": "postal_code", + "state": "state", + }, + currency="currency", email_delivery=True, - external_customer_id="string", + external_customer_id="external_customer_id", + hierarchy={ + "child_customer_ids": ["string"], + "parent_customer_id": "parent_customer_id", + }, metadata={"foo": "string"}, + payment_configuration={ + "payment_providers": [ + { + "provider_type": "stripe", + "default_shared_payment_token": "default_shared_payment_token", + "excluded_payment_method_types": ["string"], + } + ] + }, payment_provider="quickbooks", - payment_provider_id="string", + payment_provider_id="payment_provider_id", reporting_configuration={"exempt": True}, shipping_address={ - "line1": "string", - "line2": "string", - "city": "string", - "state": "string", - "postal_code": "string", - "country": "string", + "city": "city", + "country": "country", + "line1": "line1", + "line2": "line2", + "postal_code": "postal_code", + "state": "state", + }, + tax_configuration={ + "tax_exempt": True, + "tax_provider": "avalara", + "automatic_tax_enabled": True, + "tax_exemption_code": "tax_exemption_code", }, tax_id={ "country": "AD", "type": "ad_nrt", - "value": "string", + "value": "value", }, - timezone="string", + timezone="timezone", ) assert_matches_type(Customer, customer, path=["response"]) @parametrize def test_raw_response_create(self, client: Orb) -> None: response = client.customers.with_raw_response.create( - email="string", - name="string", + email="dev@stainless.com", + name="x", ) assert response.is_closed is True @@ -100,8 +112,8 @@ 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="string", - name="string", + email="dev@stainless.com", + name="x", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -114,62 +126,75 @@ def test_streaming_response_create(self, client: Orb) -> None: @parametrize def test_method_update(self, client: Orb) -> None: customer = client.customers.update( - "string", + customer_id="customer_id", ) assert_matches_type(Customer, customer, path=["response"]) @parametrize def test_method_update_with_all_params(self, client: Orb) -> None: customer = client.customers.update( - "string", + customer_id="customer_id", accounting_sync_configuration={ - "excluded": True, "accounting_providers": [ { - "provider_type": "string", - "external_provider_id": "string", - }, - { - "provider_type": "string", - "external_provider_id": "string", - }, - { - "provider_type": "string", - "external_provider_id": "string", - }, + "external_provider_id": "external_provider_id", + "provider_type": "quickbooks", + } ], + "excluded": True, }, additional_emails=["string"], auto_collection=True, + auto_issuance=True, billing_address={ - "line1": "string", - "line2": "string", - "city": "string", - "state": "string", - "postal_code": "string", - "country": "string", - }, - currency="string", - email="string", + "city": "city", + "country": "country", + "line1": "line1", + "line2": "line2", + "postal_code": "postal_code", + "state": "state", + }, + currency="currency", + default_payment_method_id="default_payment_method_id", + email="dev@stainless.com", email_delivery=True, - external_customer_id="string", + external_customer_id="external_customer_id", + hierarchy={ + "child_customer_ids": ["string"], + "parent_customer_id": "parent_customer_id", + }, metadata={"foo": "string"}, - name="string", + name="name", + payment_configuration={ + "payment_providers": [ + { + "provider_type": "stripe", + "default_shared_payment_token": "default_shared_payment_token", + "excluded_payment_method_types": ["string"], + } + ] + }, payment_provider="quickbooks", - payment_provider_id="string", + payment_provider_id="payment_provider_id", reporting_configuration={"exempt": True}, shipping_address={ - "line1": "string", - "line2": "string", - "city": "string", - "state": "string", - "postal_code": "string", - "country": "string", + "city": "city", + "country": "country", + "line1": "line1", + "line2": "line2", + "postal_code": "postal_code", + "state": "state", + }, + tax_configuration={ + "tax_exempt": True, + "tax_provider": "avalara", + "automatic_tax_enabled": True, + "tax_exemption_code": "tax_exemption_code", }, tax_id={ "country": "AD", "type": "ad_nrt", - "value": "string", + "value": "value", }, ) assert_matches_type(Customer, customer, path=["response"]) @@ -177,7 +202,7 @@ def test_method_update_with_all_params(self, client: Orb) -> None: @parametrize def test_raw_response_update(self, client: Orb) -> None: response = client.customers.with_raw_response.update( - "string", + customer_id="customer_id", ) assert response.is_closed is True @@ -188,7 +213,7 @@ def test_raw_response_update(self, client: Orb) -> None: @parametrize def test_streaming_response_update(self, client: Orb) -> None: with client.customers.with_streaming_response.update( - "string", + customer_id="customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -202,7 +227,7 @@ def test_streaming_response_update(self, client: Orb) -> None: def test_path_params_update(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): client.customers.with_raw_response.update( - "", + customer_id="", ) @parametrize @@ -217,8 +242,8 @@ def test_method_list_with_all_params(self, client: Orb) -> None: created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), - cursor="string", - limit=0, + cursor="cursor", + limit=1, ) assert_matches_type(SyncPage[Customer], customer, path=["response"]) @@ -245,14 +270,14 @@ def test_streaming_response_list(self, client: Orb) -> None: @parametrize def test_method_delete(self, client: Orb) -> None: customer = client.customers.delete( - "string", + "customer_id", ) assert customer is None @parametrize def test_raw_response_delete(self, client: Orb) -> None: response = client.customers.with_raw_response.delete( - "string", + "customer_id", ) assert response.is_closed is True @@ -263,7 +288,7 @@ def test_raw_response_delete(self, client: Orb) -> None: @parametrize def test_streaming_response_delete(self, client: Orb) -> None: with client.customers.with_streaming_response.delete( - "string", + "customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -283,14 +308,14 @@ def test_path_params_delete(self, client: Orb) -> None: @parametrize def test_method_fetch(self, client: Orb) -> None: customer = client.customers.fetch( - "string", + "customer_id", ) assert_matches_type(Customer, customer, path=["response"]) @parametrize def test_raw_response_fetch(self, client: Orb) -> None: response = client.customers.with_raw_response.fetch( - "string", + "customer_id", ) assert response.is_closed is True @@ -301,7 +326,7 @@ def test_raw_response_fetch(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch(self, client: Orb) -> None: with client.customers.with_streaming_response.fetch( - "string", + "customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -321,14 +346,14 @@ def test_path_params_fetch(self, client: Orb) -> None: @parametrize def test_method_fetch_by_external_id(self, client: Orb) -> None: customer = client.customers.fetch_by_external_id( - "string", + "external_customer_id", ) assert_matches_type(Customer, customer, path=["response"]) @parametrize def test_raw_response_fetch_by_external_id(self, client: Orb) -> None: response = client.customers.with_raw_response.fetch_by_external_id( - "string", + "external_customer_id", ) assert response.is_closed is True @@ -339,7 +364,7 @@ def test_raw_response_fetch_by_external_id(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch_by_external_id(self, client: Orb) -> None: with client.customers.with_streaming_response.fetch_by_external_id( - "string", + "external_customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -356,65 +381,154 @@ def test_path_params_fetch_by_external_id(self, client: Orb) -> None: "", ) + @parametrize + def test_method_sync_payment_methods_from_gateway(self, client: Orb) -> None: + customer = client.customers.sync_payment_methods_from_gateway( + "customer_id", + ) + assert customer is None + + @parametrize + def test_raw_response_sync_payment_methods_from_gateway(self, client: Orb) -> None: + response = client.customers.with_raw_response.sync_payment_methods_from_gateway( + "customer_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + customer = response.parse() + assert customer is None + + @parametrize + def test_streaming_response_sync_payment_methods_from_gateway(self, client: Orb) -> None: + with client.customers.with_streaming_response.sync_payment_methods_from_gateway( + "customer_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + customer = response.parse() + assert customer is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_sync_payment_methods_from_gateway(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): + client.customers.with_raw_response.sync_payment_methods_from_gateway( + "", + ) + + @parametrize + def test_method_sync_payment_methods_from_gateway_by_external_customer_id(self, client: Orb) -> None: + customer = client.customers.sync_payment_methods_from_gateway_by_external_customer_id( + "external_customer_id", + ) + assert customer is None + + @parametrize + def test_raw_response_sync_payment_methods_from_gateway_by_external_customer_id(self, client: Orb) -> None: + response = client.customers.with_raw_response.sync_payment_methods_from_gateway_by_external_customer_id( + "external_customer_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + customer = response.parse() + assert customer is None + + @parametrize + def test_streaming_response_sync_payment_methods_from_gateway_by_external_customer_id(self, client: Orb) -> None: + with client.customers.with_streaming_response.sync_payment_methods_from_gateway_by_external_customer_id( + "external_customer_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + customer = response.parse() + assert customer is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_sync_payment_methods_from_gateway_by_external_customer_id(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): + client.customers.with_raw_response.sync_payment_methods_from_gateway_by_external_customer_id( + "", + ) + @parametrize def test_method_update_by_external_id(self, client: Orb) -> None: customer = client.customers.update_by_external_id( - "string", + id="external_customer_id", ) assert_matches_type(Customer, customer, path=["response"]) @parametrize def test_method_update_by_external_id_with_all_params(self, client: Orb) -> None: customer = client.customers.update_by_external_id( - "string", + id="external_customer_id", accounting_sync_configuration={ - "excluded": True, "accounting_providers": [ { - "provider_type": "string", - "external_provider_id": "string", - }, - { - "provider_type": "string", - "external_provider_id": "string", - }, - { - "provider_type": "string", - "external_provider_id": "string", - }, + "external_provider_id": "external_provider_id", + "provider_type": "quickbooks", + } ], + "excluded": True, }, additional_emails=["string"], auto_collection=True, + auto_issuance=True, billing_address={ - "line1": "string", - "line2": "string", - "city": "string", - "state": "string", - "postal_code": "string", - "country": "string", - }, - currency="string", - email="string", + "city": "city", + "country": "country", + "line1": "line1", + "line2": "line2", + "postal_code": "postal_code", + "state": "state", + }, + currency="currency", + default_payment_method_id="default_payment_method_id", + email="dev@stainless.com", email_delivery=True, - external_customer_id="string", + external_customer_id="external_customer_id", + hierarchy={ + "child_customer_ids": ["string"], + "parent_customer_id": "parent_customer_id", + }, metadata={"foo": "string"}, - name="string", + name="name", + payment_configuration={ + "payment_providers": [ + { + "provider_type": "stripe", + "default_shared_payment_token": "default_shared_payment_token", + "excluded_payment_method_types": ["string"], + } + ] + }, payment_provider="quickbooks", - payment_provider_id="string", + payment_provider_id="payment_provider_id", reporting_configuration={"exempt": True}, shipping_address={ - "line1": "string", - "line2": "string", - "city": "string", - "state": "string", - "postal_code": "string", - "country": "string", + "city": "city", + "country": "country", + "line1": "line1", + "line2": "line2", + "postal_code": "postal_code", + "state": "state", + }, + tax_configuration={ + "tax_exempt": True, + "tax_provider": "avalara", + "automatic_tax_enabled": True, + "tax_exemption_code": "tax_exemption_code", }, tax_id={ "country": "AD", "type": "ad_nrt", - "value": "string", + "value": "value", }, ) assert_matches_type(Customer, customer, path=["response"]) @@ -422,7 +536,7 @@ def test_method_update_by_external_id_with_all_params(self, client: Orb) -> None @parametrize def test_raw_response_update_by_external_id(self, client: Orb) -> None: response = client.customers.with_raw_response.update_by_external_id( - "string", + id="external_customer_id", ) assert response.is_closed is True @@ -433,7 +547,7 @@ def test_raw_response_update_by_external_id(self, client: Orb) -> None: @parametrize def test_streaming_response_update_by_external_id(self, client: Orb) -> None: with client.customers.with_streaming_response.update_by_external_id( - "string", + id="external_customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -447,83 +561,96 @@ def test_streaming_response_update_by_external_id(self, client: Orb) -> None: def test_path_params_update_by_external_id(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): client.customers.with_raw_response.update_by_external_id( - "", - external_customer_id="", + id="", ) class TestAsyncCustomers: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOrb) -> None: customer = await async_client.customers.create( - email="string", - name="string", + email="dev@stainless.com", + name="x", ) assert_matches_type(Customer, customer, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> None: customer = await async_client.customers.create( - email="string", - name="string", + email="dev@stainless.com", + name="x", accounting_sync_configuration={ - "excluded": True, "accounting_providers": [ { - "provider_type": "string", - "external_provider_id": "string", - }, - { - "provider_type": "string", - "external_provider_id": "string", - }, - { - "provider_type": "string", - "external_provider_id": "string", - }, + "external_provider_id": "external_provider_id", + "provider_type": "quickbooks", + } ], + "excluded": True, }, - additional_emails=["string", "string", "string"], + additional_emails=["dev@stainless.com"], auto_collection=True, + auto_issuance=True, billing_address={ - "line1": "string", - "line2": "string", - "city": "string", - "state": "string", - "postal_code": "string", - "country": "string", - }, - currency="string", + "city": "city", + "country": "country", + "line1": "line1", + "line2": "line2", + "postal_code": "postal_code", + "state": "state", + }, + currency="currency", email_delivery=True, - external_customer_id="string", + external_customer_id="external_customer_id", + hierarchy={ + "child_customer_ids": ["string"], + "parent_customer_id": "parent_customer_id", + }, metadata={"foo": "string"}, + payment_configuration={ + "payment_providers": [ + { + "provider_type": "stripe", + "default_shared_payment_token": "default_shared_payment_token", + "excluded_payment_method_types": ["string"], + } + ] + }, payment_provider="quickbooks", - payment_provider_id="string", + payment_provider_id="payment_provider_id", reporting_configuration={"exempt": True}, shipping_address={ - "line1": "string", - "line2": "string", - "city": "string", - "state": "string", - "postal_code": "string", - "country": "string", + "city": "city", + "country": "country", + "line1": "line1", + "line2": "line2", + "postal_code": "postal_code", + "state": "state", + }, + tax_configuration={ + "tax_exempt": True, + "tax_provider": "avalara", + "automatic_tax_enabled": True, + "tax_exemption_code": "tax_exemption_code", }, tax_id={ "country": "AD", "type": "ad_nrt", - "value": "string", + "value": "value", }, - timezone="string", + timezone="timezone", ) assert_matches_type(Customer, customer, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncOrb) -> None: response = await async_client.customers.with_raw_response.create( - email="string", - name="string", + email="dev@stainless.com", + name="x", ) assert response.is_closed is True @@ -534,8 +661,8 @@ 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="string", - name="string", + email="dev@stainless.com", + name="x", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -548,62 +675,75 @@ async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_update(self, async_client: AsyncOrb) -> None: customer = await async_client.customers.update( - "string", + customer_id="customer_id", ) assert_matches_type(Customer, customer, path=["response"]) @parametrize async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> None: customer = await async_client.customers.update( - "string", + customer_id="customer_id", accounting_sync_configuration={ - "excluded": True, "accounting_providers": [ { - "provider_type": "string", - "external_provider_id": "string", - }, - { - "provider_type": "string", - "external_provider_id": "string", - }, - { - "provider_type": "string", - "external_provider_id": "string", - }, + "external_provider_id": "external_provider_id", + "provider_type": "quickbooks", + } ], + "excluded": True, }, additional_emails=["string"], auto_collection=True, + auto_issuance=True, billing_address={ - "line1": "string", - "line2": "string", - "city": "string", - "state": "string", - "postal_code": "string", - "country": "string", - }, - currency="string", - email="string", + "city": "city", + "country": "country", + "line1": "line1", + "line2": "line2", + "postal_code": "postal_code", + "state": "state", + }, + currency="currency", + default_payment_method_id="default_payment_method_id", + email="dev@stainless.com", email_delivery=True, - external_customer_id="string", + external_customer_id="external_customer_id", + hierarchy={ + "child_customer_ids": ["string"], + "parent_customer_id": "parent_customer_id", + }, metadata={"foo": "string"}, - name="string", + name="name", + payment_configuration={ + "payment_providers": [ + { + "provider_type": "stripe", + "default_shared_payment_token": "default_shared_payment_token", + "excluded_payment_method_types": ["string"], + } + ] + }, payment_provider="quickbooks", - payment_provider_id="string", + payment_provider_id="payment_provider_id", reporting_configuration={"exempt": True}, shipping_address={ - "line1": "string", - "line2": "string", - "city": "string", - "state": "string", - "postal_code": "string", - "country": "string", + "city": "city", + "country": "country", + "line1": "line1", + "line2": "line2", + "postal_code": "postal_code", + "state": "state", + }, + tax_configuration={ + "tax_exempt": True, + "tax_provider": "avalara", + "automatic_tax_enabled": True, + "tax_exemption_code": "tax_exemption_code", }, tax_id={ "country": "AD", "type": "ad_nrt", - "value": "string", + "value": "value", }, ) assert_matches_type(Customer, customer, path=["response"]) @@ -611,7 +751,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> No @parametrize async def test_raw_response_update(self, async_client: AsyncOrb) -> None: response = await async_client.customers.with_raw_response.update( - "string", + customer_id="customer_id", ) assert response.is_closed is True @@ -622,7 +762,7 @@ async def test_raw_response_update(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: async with async_client.customers.with_streaming_response.update( - "string", + customer_id="customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -636,7 +776,7 @@ async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: async def test_path_params_update(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): await async_client.customers.with_raw_response.update( - "", + customer_id="", ) @parametrize @@ -651,8 +791,8 @@ async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), - cursor="string", - limit=0, + cursor="cursor", + limit=1, ) assert_matches_type(AsyncPage[Customer], customer, path=["response"]) @@ -679,14 +819,14 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_delete(self, async_client: AsyncOrb) -> None: customer = await async_client.customers.delete( - "string", + "customer_id", ) assert customer is None @parametrize async def test_raw_response_delete(self, async_client: AsyncOrb) -> None: response = await async_client.customers.with_raw_response.delete( - "string", + "customer_id", ) assert response.is_closed is True @@ -697,7 +837,7 @@ async def test_raw_response_delete(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_delete(self, async_client: AsyncOrb) -> None: async with async_client.customers.with_streaming_response.delete( - "string", + "customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -717,14 +857,14 @@ async def test_path_params_delete(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_fetch(self, async_client: AsyncOrb) -> None: customer = await async_client.customers.fetch( - "string", + "customer_id", ) assert_matches_type(Customer, customer, path=["response"]) @parametrize async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: response = await async_client.customers.with_raw_response.fetch( - "string", + "customer_id", ) assert response.is_closed is True @@ -735,7 +875,7 @@ async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_fetch(self, async_client: AsyncOrb) -> None: async with async_client.customers.with_streaming_response.fetch( - "string", + "customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -755,14 +895,14 @@ async def test_path_params_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_fetch_by_external_id(self, async_client: AsyncOrb) -> None: customer = await async_client.customers.fetch_by_external_id( - "string", + "external_customer_id", ) assert_matches_type(Customer, customer, path=["response"]) @parametrize async def test_raw_response_fetch_by_external_id(self, async_client: AsyncOrb) -> None: response = await async_client.customers.with_raw_response.fetch_by_external_id( - "string", + "external_customer_id", ) assert response.is_closed is True @@ -773,7 +913,7 @@ async def test_raw_response_fetch_by_external_id(self, async_client: AsyncOrb) - @parametrize async def test_streaming_response_fetch_by_external_id(self, async_client: AsyncOrb) -> None: async with async_client.customers.with_streaming_response.fetch_by_external_id( - "string", + "external_customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -790,65 +930,166 @@ async def test_path_params_fetch_by_external_id(self, async_client: AsyncOrb) -> "", ) + @parametrize + async def test_method_sync_payment_methods_from_gateway(self, async_client: AsyncOrb) -> None: + customer = await async_client.customers.sync_payment_methods_from_gateway( + "customer_id", + ) + assert customer is None + + @parametrize + async def test_raw_response_sync_payment_methods_from_gateway(self, async_client: AsyncOrb) -> None: + response = await async_client.customers.with_raw_response.sync_payment_methods_from_gateway( + "customer_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + customer = response.parse() + assert customer is None + + @parametrize + async def test_streaming_response_sync_payment_methods_from_gateway(self, async_client: AsyncOrb) -> None: + async with async_client.customers.with_streaming_response.sync_payment_methods_from_gateway( + "customer_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + customer = await response.parse() + assert customer is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_sync_payment_methods_from_gateway(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): + await async_client.customers.with_raw_response.sync_payment_methods_from_gateway( + "", + ) + + @parametrize + async def test_method_sync_payment_methods_from_gateway_by_external_customer_id( + self, async_client: AsyncOrb + ) -> None: + customer = await async_client.customers.sync_payment_methods_from_gateway_by_external_customer_id( + "external_customer_id", + ) + assert customer is None + + @parametrize + async def test_raw_response_sync_payment_methods_from_gateway_by_external_customer_id( + self, async_client: AsyncOrb + ) -> None: + response = ( + await async_client.customers.with_raw_response.sync_payment_methods_from_gateway_by_external_customer_id( + "external_customer_id", + ) + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + customer = response.parse() + assert customer is None + + @parametrize + async def test_streaming_response_sync_payment_methods_from_gateway_by_external_customer_id( + self, async_client: AsyncOrb + ) -> None: + async with ( + async_client.customers.with_streaming_response.sync_payment_methods_from_gateway_by_external_customer_id( + "external_customer_id", + ) + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + customer = await response.parse() + assert customer is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_sync_payment_methods_from_gateway_by_external_customer_id( + self, async_client: AsyncOrb + ) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_customer_id` but received ''"): + await async_client.customers.with_raw_response.sync_payment_methods_from_gateway_by_external_customer_id( + "", + ) + @parametrize async def test_method_update_by_external_id(self, async_client: AsyncOrb) -> None: customer = await async_client.customers.update_by_external_id( - "string", + id="external_customer_id", ) assert_matches_type(Customer, customer, path=["response"]) @parametrize async def test_method_update_by_external_id_with_all_params(self, async_client: AsyncOrb) -> None: customer = await async_client.customers.update_by_external_id( - "string", + id="external_customer_id", accounting_sync_configuration={ - "excluded": True, "accounting_providers": [ { - "provider_type": "string", - "external_provider_id": "string", - }, - { - "provider_type": "string", - "external_provider_id": "string", - }, - { - "provider_type": "string", - "external_provider_id": "string", - }, + "external_provider_id": "external_provider_id", + "provider_type": "quickbooks", + } ], + "excluded": True, }, additional_emails=["string"], auto_collection=True, + auto_issuance=True, billing_address={ - "line1": "string", - "line2": "string", - "city": "string", - "state": "string", - "postal_code": "string", - "country": "string", - }, - currency="string", - email="string", + "city": "city", + "country": "country", + "line1": "line1", + "line2": "line2", + "postal_code": "postal_code", + "state": "state", + }, + currency="currency", + default_payment_method_id="default_payment_method_id", + email="dev@stainless.com", email_delivery=True, - external_customer_id="string", + external_customer_id="external_customer_id", + hierarchy={ + "child_customer_ids": ["string"], + "parent_customer_id": "parent_customer_id", + }, metadata={"foo": "string"}, - name="string", + name="name", + payment_configuration={ + "payment_providers": [ + { + "provider_type": "stripe", + "default_shared_payment_token": "default_shared_payment_token", + "excluded_payment_method_types": ["string"], + } + ] + }, payment_provider="quickbooks", - payment_provider_id="string", + payment_provider_id="payment_provider_id", reporting_configuration={"exempt": True}, shipping_address={ - "line1": "string", - "line2": "string", - "city": "string", - "state": "string", - "postal_code": "string", - "country": "string", + "city": "city", + "country": "country", + "line1": "line1", + "line2": "line2", + "postal_code": "postal_code", + "state": "state", + }, + tax_configuration={ + "tax_exempt": True, + "tax_provider": "avalara", + "automatic_tax_enabled": True, + "tax_exemption_code": "tax_exemption_code", }, tax_id={ "country": "AD", "type": "ad_nrt", - "value": "string", + "value": "value", }, ) assert_matches_type(Customer, customer, path=["response"]) @@ -856,7 +1097,7 @@ async def test_method_update_by_external_id_with_all_params(self, async_client: @parametrize async def test_raw_response_update_by_external_id(self, async_client: AsyncOrb) -> None: response = await async_client.customers.with_raw_response.update_by_external_id( - "string", + id="external_customer_id", ) assert response.is_closed is True @@ -867,7 +1108,7 @@ async def test_raw_response_update_by_external_id(self, async_client: AsyncOrb) @parametrize async def test_streaming_response_update_by_external_id(self, async_client: AsyncOrb) -> None: async with async_client.customers.with_streaming_response.update_by_external_id( - "string", + id="external_customer_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -881,6 +1122,5 @@ async def test_streaming_response_update_by_external_id(self, async_client: Asyn async def test_path_params_update_by_external_id(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): await async_client.customers.with_raw_response.update_by_external_id( - "", - external_customer_id="", + id="", ) diff --git a/tests/api_resources/test_dimensional_price_groups.py b/tests/api_resources/test_dimensional_price_groups.py new file mode 100644 index 00000000..8fa526b7 --- /dev/null +++ b/tests/api_resources/test_dimensional_price_groups.py @@ -0,0 +1,367 @@ +# 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.types import ( + DimensionalPriceGroup, +) +from tests.utils import assert_matches_type +from orb.pagination import SyncPage, AsyncPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDimensionalPriceGroups: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Orb) -> None: + dimensional_price_group = client.dimensional_price_groups.create( + billable_metric_id="billable_metric_id", + dimensions=["region", "instance_type"], + name="name", + ) + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Orb) -> None: + dimensional_price_group = client.dimensional_price_groups.create( + billable_metric_id="billable_metric_id", + dimensions=["region", "instance_type"], + name="name", + external_dimensional_price_group_id="external_dimensional_price_group_id", + metadata={"foo": "string"}, + ) + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Orb) -> None: + response = client.dimensional_price_groups.with_raw_response.create( + billable_metric_id="billable_metric_id", + dimensions=["region", "instance_type"], + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dimensional_price_group = response.parse() + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Orb) -> None: + with client.dimensional_price_groups.with_streaming_response.create( + billable_metric_id="billable_metric_id", + dimensions=["region", "instance_type"], + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dimensional_price_group = response.parse() + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: Orb) -> None: + dimensional_price_group = client.dimensional_price_groups.retrieve( + "dimensional_price_group_id", + ) + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: Orb) -> None: + response = client.dimensional_price_groups.with_raw_response.retrieve( + "dimensional_price_group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dimensional_price_group = response.parse() + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: Orb) -> None: + with client.dimensional_price_groups.with_streaming_response.retrieve( + "dimensional_price_group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dimensional_price_group = response.parse() + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: Orb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `dimensional_price_group_id` but received ''" + ): + client.dimensional_price_groups.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: Orb) -> None: + dimensional_price_group = client.dimensional_price_groups.update( + dimensional_price_group_id="dimensional_price_group_id", + ) + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Orb) -> None: + dimensional_price_group = client.dimensional_price_groups.update( + dimensional_price_group_id="dimensional_price_group_id", + external_dimensional_price_group_id="external_dimensional_price_group_id", + metadata={"foo": "string"}, + ) + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Orb) -> None: + response = client.dimensional_price_groups.with_raw_response.update( + dimensional_price_group_id="dimensional_price_group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dimensional_price_group = response.parse() + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Orb) -> None: + with client.dimensional_price_groups.with_streaming_response.update( + dimensional_price_group_id="dimensional_price_group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dimensional_price_group = response.parse() + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Orb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `dimensional_price_group_id` but received ''" + ): + client.dimensional_price_groups.with_raw_response.update( + dimensional_price_group_id="", + ) + + @parametrize + def test_method_list(self, client: Orb) -> None: + dimensional_price_group = client.dimensional_price_groups.list() + assert_matches_type(SyncPage[DimensionalPriceGroup], dimensional_price_group, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Orb) -> None: + dimensional_price_group = client.dimensional_price_groups.list( + cursor="cursor", + limit=1, + ) + assert_matches_type(SyncPage[DimensionalPriceGroup], dimensional_price_group, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Orb) -> None: + response = client.dimensional_price_groups.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dimensional_price_group = response.parse() + assert_matches_type(SyncPage[DimensionalPriceGroup], dimensional_price_group, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Orb) -> None: + with client.dimensional_price_groups.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dimensional_price_group = response.parse() + assert_matches_type(SyncPage[DimensionalPriceGroup], dimensional_price_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncDimensionalPriceGroups: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOrb) -> None: + dimensional_price_group = await async_client.dimensional_price_groups.create( + billable_metric_id="billable_metric_id", + dimensions=["region", "instance_type"], + name="name", + ) + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> None: + dimensional_price_group = await async_client.dimensional_price_groups.create( + billable_metric_id="billable_metric_id", + dimensions=["region", "instance_type"], + name="name", + external_dimensional_price_group_id="external_dimensional_price_group_id", + metadata={"foo": "string"}, + ) + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOrb) -> None: + response = await async_client.dimensional_price_groups.with_raw_response.create( + billable_metric_id="billable_metric_id", + dimensions=["region", "instance_type"], + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dimensional_price_group = response.parse() + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: + async with async_client.dimensional_price_groups.with_streaming_response.create( + billable_metric_id="billable_metric_id", + dimensions=["region", "instance_type"], + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dimensional_price_group = await response.parse() + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOrb) -> None: + dimensional_price_group = await async_client.dimensional_price_groups.retrieve( + "dimensional_price_group_id", + ) + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOrb) -> None: + response = await async_client.dimensional_price_groups.with_raw_response.retrieve( + "dimensional_price_group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dimensional_price_group = response.parse() + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOrb) -> None: + async with async_client.dimensional_price_groups.with_streaming_response.retrieve( + "dimensional_price_group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dimensional_price_group = await response.parse() + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOrb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `dimensional_price_group_id` but received ''" + ): + await async_client.dimensional_price_groups.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncOrb) -> None: + dimensional_price_group = await async_client.dimensional_price_groups.update( + dimensional_price_group_id="dimensional_price_group_id", + ) + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> None: + dimensional_price_group = await async_client.dimensional_price_groups.update( + dimensional_price_group_id="dimensional_price_group_id", + external_dimensional_price_group_id="external_dimensional_price_group_id", + metadata={"foo": "string"}, + ) + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOrb) -> None: + response = await async_client.dimensional_price_groups.with_raw_response.update( + dimensional_price_group_id="dimensional_price_group_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dimensional_price_group = response.parse() + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: + async with async_client.dimensional_price_groups.with_streaming_response.update( + dimensional_price_group_id="dimensional_price_group_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dimensional_price_group = await response.parse() + assert_matches_type(DimensionalPriceGroup, dimensional_price_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOrb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `dimensional_price_group_id` but received ''" + ): + await async_client.dimensional_price_groups.with_raw_response.update( + dimensional_price_group_id="", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOrb) -> None: + dimensional_price_group = await async_client.dimensional_price_groups.list() + assert_matches_type(AsyncPage[DimensionalPriceGroup], dimensional_price_group, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: + dimensional_price_group = await async_client.dimensional_price_groups.list( + cursor="cursor", + limit=1, + ) + assert_matches_type(AsyncPage[DimensionalPriceGroup], dimensional_price_group, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOrb) -> None: + response = await async_client.dimensional_price_groups.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dimensional_price_group = response.parse() + assert_matches_type(AsyncPage[DimensionalPriceGroup], dimensional_price_group, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: + async with async_client.dimensional_price_groups.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dimensional_price_group = await response.parse() + assert_matches_type(AsyncPage[DimensionalPriceGroup], dimensional_price_group, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_events.py b/tests/api_resources/test_events.py index 1347a5d1..6aab2662 100644 --- a/tests/api_resources/test_events.py +++ b/tests/api_resources/test_events.py @@ -26,9 +26,9 @@ class TestEvents: @parametrize def test_method_update(self, client: Orb) -> None: event = client.events.update( - "string", - event_name="string", - properties={}, + event_id="event_id", + event_name="event_name", + properties={"foo": "bar"}, timestamp=parse_datetime("2020-12-09T16:09:53Z"), ) assert_matches_type(EventUpdateResponse, event, path=["response"]) @@ -36,21 +36,21 @@ def test_method_update(self, client: Orb) -> None: @parametrize def test_method_update_with_all_params(self, client: Orb) -> None: event = client.events.update( - "string", - event_name="string", - properties={}, + event_id="event_id", + event_name="event_name", + properties={"foo": "bar"}, timestamp=parse_datetime("2020-12-09T16:09:53Z"), - customer_id="string", - external_customer_id="string", + customer_id="customer_id", + external_customer_id="external_customer_id", ) assert_matches_type(EventUpdateResponse, event, path=["response"]) @parametrize def test_raw_response_update(self, client: Orb) -> None: response = client.events.with_raw_response.update( - "string", - event_name="string", - properties={}, + event_id="event_id", + event_name="event_name", + properties={"foo": "bar"}, timestamp=parse_datetime("2020-12-09T16:09:53Z"), ) @@ -62,9 +62,9 @@ def test_raw_response_update(self, client: Orb) -> None: @parametrize def test_streaming_response_update(self, client: Orb) -> None: with client.events.with_streaming_response.update( - "string", - event_name="string", - properties={}, + event_id="event_id", + event_name="event_name", + properties={"foo": "bar"}, timestamp=parse_datetime("2020-12-09T16:09:53Z"), ) as response: assert not response.is_closed @@ -79,23 +79,23 @@ def test_streaming_response_update(self, client: Orb) -> None: def test_path_params_update(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `event_id` but received ''"): client.events.with_raw_response.update( - "", - event_name="string", - properties={}, + event_id="", + event_name="event_name", + properties={"foo": "bar"}, timestamp=parse_datetime("2020-12-09T16:09:53Z"), ) @parametrize def test_method_deprecate(self, client: Orb) -> None: event = client.events.deprecate( - "string", + "event_id", ) assert_matches_type(EventDeprecateResponse, event, path=["response"]) @parametrize def test_raw_response_deprecate(self, client: Orb) -> None: response = client.events.with_raw_response.deprecate( - "string", + "event_id", ) assert response.is_closed is True @@ -106,7 +106,7 @@ def test_raw_response_deprecate(self, client: Orb) -> None: @parametrize def test_streaming_response_deprecate(self, client: Orb) -> None: with client.events.with_streaming_response.deprecate( - "string", + "event_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -128,23 +128,11 @@ def test_method_ingest(self, client: Orb) -> None: event = client.events.ingest( events=[ { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "event_name": "string", + "event_name": "event_name", + "idempotency_key": "idempotency_key", + "properties": {"foo": "bar"}, "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, + } ], ) assert_matches_type(EventIngestResponse, event, path=["response"]) @@ -154,31 +142,15 @@ def test_method_ingest_with_all_params(self, client: Orb) -> None: event = client.events.ingest( events=[ { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", + "event_name": "event_name", + "idempotency_key": "idempotency_key", + "properties": {"foo": "bar"}, "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, + "customer_id": "customer_id", + "external_customer_id": "external_customer_id", + } ], - backfill_id="string", + backfill_id="backfill_id", debug=True, ) assert_matches_type(EventIngestResponse, event, path=["response"]) @@ -188,23 +160,11 @@ def test_raw_response_ingest(self, client: Orb) -> None: response = client.events.with_raw_response.ingest( events=[ { - "event_name": "string", + "event_name": "event_name", + "idempotency_key": "idempotency_key", + "properties": {"foo": "bar"}, "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, + } ], ) @@ -218,23 +178,11 @@ def test_streaming_response_ingest(self, client: Orb) -> None: with client.events.with_streaming_response.ingest( events=[ { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "event_name": "string", + "event_name": "event_name", + "idempotency_key": "idempotency_key", + "properties": {"foo": "bar"}, "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, + } ], ) as response: assert not response.is_closed @@ -287,14 +235,16 @@ def test_streaming_response_search(self, client: Orb) -> None: class TestAsyncEvents: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_update(self, async_client: AsyncOrb) -> None: event = await async_client.events.update( - "string", - event_name="string", - properties={}, + event_id="event_id", + event_name="event_name", + properties={"foo": "bar"}, timestamp=parse_datetime("2020-12-09T16:09:53Z"), ) assert_matches_type(EventUpdateResponse, event, path=["response"]) @@ -302,21 +252,21 @@ async def test_method_update(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> None: event = await async_client.events.update( - "string", - event_name="string", - properties={}, + event_id="event_id", + event_name="event_name", + properties={"foo": "bar"}, timestamp=parse_datetime("2020-12-09T16:09:53Z"), - customer_id="string", - external_customer_id="string", + customer_id="customer_id", + external_customer_id="external_customer_id", ) assert_matches_type(EventUpdateResponse, event, path=["response"]) @parametrize async def test_raw_response_update(self, async_client: AsyncOrb) -> None: response = await async_client.events.with_raw_response.update( - "string", - event_name="string", - properties={}, + event_id="event_id", + event_name="event_name", + properties={"foo": "bar"}, timestamp=parse_datetime("2020-12-09T16:09:53Z"), ) @@ -328,9 +278,9 @@ async def test_raw_response_update(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: async with async_client.events.with_streaming_response.update( - "string", - event_name="string", - properties={}, + event_id="event_id", + event_name="event_name", + properties={"foo": "bar"}, timestamp=parse_datetime("2020-12-09T16:09:53Z"), ) as response: assert not response.is_closed @@ -345,23 +295,23 @@ async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: async def test_path_params_update(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `event_id` but received ''"): await async_client.events.with_raw_response.update( - "", - event_name="string", - properties={}, + event_id="", + event_name="event_name", + properties={"foo": "bar"}, timestamp=parse_datetime("2020-12-09T16:09:53Z"), ) @parametrize async def test_method_deprecate(self, async_client: AsyncOrb) -> None: event = await async_client.events.deprecate( - "string", + "event_id", ) assert_matches_type(EventDeprecateResponse, event, path=["response"]) @parametrize async def test_raw_response_deprecate(self, async_client: AsyncOrb) -> None: response = await async_client.events.with_raw_response.deprecate( - "string", + "event_id", ) assert response.is_closed is True @@ -372,7 +322,7 @@ async def test_raw_response_deprecate(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_deprecate(self, async_client: AsyncOrb) -> None: async with async_client.events.with_streaming_response.deprecate( - "string", + "event_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -394,23 +344,11 @@ async def test_method_ingest(self, async_client: AsyncOrb) -> None: event = await async_client.events.ingest( events=[ { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "event_name": "string", + "event_name": "event_name", + "idempotency_key": "idempotency_key", + "properties": {"foo": "bar"}, "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, + } ], ) assert_matches_type(EventIngestResponse, event, path=["response"]) @@ -420,31 +358,15 @@ async def test_method_ingest_with_all_params(self, async_client: AsyncOrb) -> No event = await async_client.events.ingest( events=[ { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "customer_id": "string", - "external_customer_id": "string", - "event_name": "string", + "event_name": "event_name", + "idempotency_key": "idempotency_key", + "properties": {"foo": "bar"}, "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, + "customer_id": "customer_id", + "external_customer_id": "external_customer_id", + } ], - backfill_id="string", + backfill_id="backfill_id", debug=True, ) assert_matches_type(EventIngestResponse, event, path=["response"]) @@ -454,23 +376,11 @@ async def test_raw_response_ingest(self, async_client: AsyncOrb) -> None: response = await async_client.events.with_raw_response.ingest( events=[ { - "event_name": "string", + "event_name": "event_name", + "idempotency_key": "idempotency_key", + "properties": {"foo": "bar"}, "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, + } ], ) @@ -484,23 +394,11 @@ async def test_streaming_response_ingest(self, async_client: AsyncOrb) -> None: async with async_client.events.with_streaming_response.ingest( events=[ { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "event_name": "string", - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, - { - "event_name": "string", + "event_name": "event_name", + "idempotency_key": "idempotency_key", + "properties": {"foo": "bar"}, "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "properties": {}, - "idempotency_key": "string", - }, + } ], ) as response: assert not response.is_closed diff --git a/tests/api_resources/test_invoice_line_items.py b/tests/api_resources/test_invoice_line_items.py index 55411e85..4cf8e001 100644 --- a/tests/api_resources/test_invoice_line_items.py +++ b/tests/api_resources/test_invoice_line_items.py @@ -24,19 +24,30 @@ def test_method_create(self, client: Orb) -> None: amount="12.00", end_date=parse_date("2023-09-22"), invoice_id="4khy3nwzktxv7", - name="Item Name", quantity=1, start_date=parse_date("2023-09-22"), ) assert_matches_type(InvoiceLineItemCreateResponse, invoice_line_item, path=["response"]) + @parametrize + def test_method_create_with_all_params(self, client: Orb) -> None: + invoice_line_item = client.invoice_line_items.create( + amount="12.00", + end_date=parse_date("2023-09-22"), + invoice_id="4khy3nwzktxv7", + quantity=1, + start_date=parse_date("2023-09-22"), + item_id="4khy3nwzktxv7", + name="Item Name", + ) + assert_matches_type(InvoiceLineItemCreateResponse, invoice_line_item, path=["response"]) + @parametrize def test_raw_response_create(self, client: Orb) -> None: response = client.invoice_line_items.with_raw_response.create( amount="12.00", end_date=parse_date("2023-09-22"), invoice_id="4khy3nwzktxv7", - name="Item Name", quantity=1, start_date=parse_date("2023-09-22"), ) @@ -52,7 +63,6 @@ def test_streaming_response_create(self, client: Orb) -> None: amount="12.00", end_date=parse_date("2023-09-22"), invoice_id="4khy3nwzktxv7", - name="Item Name", quantity=1, start_date=parse_date("2023-09-22"), ) as response: @@ -66,7 +76,9 @@ def test_streaming_response_create(self, client: Orb) -> None: class TestAsyncInvoiceLineItems: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOrb) -> None: @@ -74,19 +86,30 @@ async def test_method_create(self, async_client: AsyncOrb) -> None: amount="12.00", end_date=parse_date("2023-09-22"), invoice_id="4khy3nwzktxv7", - name="Item Name", quantity=1, start_date=parse_date("2023-09-22"), ) assert_matches_type(InvoiceLineItemCreateResponse, invoice_line_item, path=["response"]) + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> None: + invoice_line_item = await async_client.invoice_line_items.create( + amount="12.00", + end_date=parse_date("2023-09-22"), + invoice_id="4khy3nwzktxv7", + quantity=1, + start_date=parse_date("2023-09-22"), + item_id="4khy3nwzktxv7", + name="Item Name", + ) + assert_matches_type(InvoiceLineItemCreateResponse, invoice_line_item, path=["response"]) + @parametrize async def test_raw_response_create(self, async_client: AsyncOrb) -> None: response = await async_client.invoice_line_items.with_raw_response.create( amount="12.00", end_date=parse_date("2023-09-22"), invoice_id="4khy3nwzktxv7", - name="Item Name", quantity=1, start_date=parse_date("2023-09-22"), ) @@ -102,7 +125,6 @@ async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: amount="12.00", end_date=parse_date("2023-09-22"), invoice_id="4khy3nwzktxv7", - name="Item Name", quantity=1, start_date=parse_date("2023-09-22"), ) as response: diff --git a/tests/api_resources/test_invoices.py b/tests/api_resources/test_invoices.py index 436577e6..8eb7e18e 100644 --- a/tests/api_resources/test_invoices.py +++ b/tests/api_resources/test_invoices.py @@ -9,12 +9,14 @@ from orb import Orb, AsyncOrb from orb.types import ( - Invoice, + InvoiceListSummaryResponse, + InvoiceIssueSummaryResponse, InvoiceFetchUpcomingResponse, ) from orb._utils import parse_date, parse_datetime from tests.utils import assert_matches_type from orb.pagination import SyncPage, AsyncPage +from orb.types.shared import Invoice base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -29,34 +31,15 @@ def test_method_create(self, client: Orb) -> None: invoice_date=parse_datetime("2019-12-27T18:11:19.117Z"), line_items=[ { - "start_date": parse_date("2023-09-22"), "end_date": parse_date("2023-09-22"), - "quantity": 1, - "name": "Line Item Name", "item_id": "4khy3nwzktxv7", "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), - "quantity": 1, "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), "quantity": 1, - "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, + "start_date": parse_date("2023-09-22"), + "unit_config": {"unit_amount": "unit_amount"}, + } ], - net_terms=0, ) assert_matches_type(Invoice, invoice, path=["response"]) @@ -67,38 +50,38 @@ def test_method_create_with_all_params(self, client: Orb) -> None: invoice_date=parse_datetime("2019-12-27T18:11:19.117Z"), line_items=[ { - "start_date": parse_date("2023-09-22"), "end_date": parse_date("2023-09-22"), - "quantity": 1, - "name": "Line Item Name", "item_id": "4khy3nwzktxv7", "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), - "quantity": 1, "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), "quantity": 1, - "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, + "start_date": parse_date("2023-09-22"), + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + } ], - net_terms=0, + auto_collection=True, customer_id="4khy3nwzktxv7", + discount={ + "discount_type": "percentage", + "percentage_discount": 0.15, + "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "reason": "reason", + }, + due_date=parse_date("2025-09-22"), external_customer_id="external-customer-id", memo="An optional memo for my invoice.", metadata={"foo": "string"}, + net_terms=0, will_auto_issue=False, ) assert_matches_type(Invoice, invoice, path=["response"]) @@ -110,34 +93,15 @@ def test_raw_response_create(self, client: Orb) -> None: invoice_date=parse_datetime("2019-12-27T18:11:19.117Z"), line_items=[ { - "start_date": parse_date("2023-09-22"), "end_date": parse_date("2023-09-22"), - "quantity": 1, - "name": "Line Item Name", "item_id": "4khy3nwzktxv7", "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), - "quantity": 1, "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), "quantity": 1, - "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, + "start_date": parse_date("2023-09-22"), + "unit_config": {"unit_amount": "unit_amount"}, + } ], - net_terms=0, ) assert response.is_closed is True @@ -152,34 +116,58 @@ def test_streaming_response_create(self, client: Orb) -> None: invoice_date=parse_datetime("2019-12-27T18:11:19.117Z"), line_items=[ { - "start_date": parse_date("2023-09-22"), "end_date": parse_date("2023-09-22"), - "quantity": 1, - "name": "Line Item Name", "item_id": "4khy3nwzktxv7", "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), - "quantity": 1, "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), "quantity": 1, - "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, + "start_date": parse_date("2023-09-22"), + "unit_config": {"unit_amount": "unit_amount"}, + } ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invoice = response.parse() + assert_matches_type(Invoice, invoice, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Orb) -> None: + invoice = client.invoices.update( + invoice_id="invoice_id", + ) + assert_matches_type(Invoice, invoice, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Orb) -> None: + invoice = client.invoices.update( + invoice_id="invoice_id", + auto_collection=True, + due_date=parse_date("2023-09-22"), + invoice_date=parse_date("2023-09-22"), + metadata={"foo": "string"}, net_terms=0, + ) + assert_matches_type(Invoice, invoice, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Orb) -> None: + response = client.invoices.with_raw_response.update( + invoice_id="invoice_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invoice = response.parse() + assert_matches_type(Invoice, invoice, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Orb) -> None: + with client.invoices.with_streaming_response.update( + invoice_id="invoice_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -189,6 +177,13 @@ def test_streaming_response_create(self, client: Orb) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_path_params_update(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.update( + invoice_id="", + ) + @parametrize def test_method_list(self, client: Orb) -> None: invoice = client.invoices.list() @@ -197,25 +192,25 @@ def test_method_list(self, client: Orb) -> None: @parametrize def test_method_list_with_all_params(self, client: Orb) -> None: invoice = client.invoices.list( - amount="string", - amount_gt="string", - amount_lt="string", - cursor="string", - customer_id="string", + amount="amount", + amount_gt="amount[gt]", + amount_lt="amount[lt]", + cursor="cursor", + customer_id="customer_id", date_type="due_date", due_date=parse_date("2019-12-27"), - due_date_window="string", + due_date_window="due_date_window", due_date_gt=parse_date("2019-12-27"), due_date_lt=parse_date("2019-12-27"), - external_customer_id="string", + external_customer_id="external_customer_id", invoice_date_gt=parse_datetime("2019-12-27T18:11:19.117Z"), invoice_date_gte=parse_datetime("2019-12-27T18:11:19.117Z"), invoice_date_lt=parse_datetime("2019-12-27T18:11:19.117Z"), invoice_date_lte=parse_datetime("2019-12-27T18:11:19.117Z"), is_recurring=True, - limit=0, - status=["draft", "issued", "paid"], - subscription_id="string", + limit=1, + status=["draft"], + subscription_id="subscription_id", ) assert_matches_type(SyncPage[Invoice], invoice, path=["response"]) @@ -239,17 +234,65 @@ def test_streaming_response_list(self, client: Orb) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_delete_line_item(self, client: Orb) -> None: + invoice = client.invoices.delete_line_item( + line_item_id="line_item_id", + invoice_id="invoice_id", + ) + assert invoice is None + + @parametrize + def test_raw_response_delete_line_item(self, client: Orb) -> None: + response = client.invoices.with_raw_response.delete_line_item( + line_item_id="line_item_id", + invoice_id="invoice_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invoice = response.parse() + assert invoice is None + + @parametrize + def test_streaming_response_delete_line_item(self, client: Orb) -> None: + with client.invoices.with_streaming_response.delete_line_item( + line_item_id="line_item_id", + invoice_id="invoice_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invoice = response.parse() + assert invoice is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete_line_item(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.delete_line_item( + line_item_id="line_item_id", + invoice_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `line_item_id` but received ''"): + client.invoices.with_raw_response.delete_line_item( + line_item_id="", + invoice_id="invoice_id", + ) + @parametrize def test_method_fetch(self, client: Orb) -> None: invoice = client.invoices.fetch( - "string", + "invoice_id", ) assert_matches_type(Invoice, invoice, path=["response"]) @parametrize def test_raw_response_fetch(self, client: Orb) -> None: response = client.invoices.with_raw_response.fetch( - "string", + "invoice_id", ) assert response.is_closed is True @@ -260,7 +303,7 @@ def test_raw_response_fetch(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch(self, client: Orb) -> None: with client.invoices.with_streaming_response.fetch( - "string", + "invoice_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -279,19 +322,16 @@ 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="string", + subscription_id="subscription_id", ) assert_matches_type(InvoiceFetchUpcomingResponse, invoice, path=["response"]) @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" @@ -300,7 +340,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" @@ -312,14 +354,22 @@ def test_streaming_response_fetch_upcoming(self, client: Orb) -> None: @parametrize def test_method_issue(self, client: Orb) -> None: invoice = client.invoices.issue( - "string", + 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( - "string", + invoice_id="invoice_id", ) assert response.is_closed is True @@ -330,7 +380,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( - "string", + invoice_id="invoice_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -344,13 +394,109 @@ 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 + def test_method_issue_summary(self, client: Orb) -> None: + invoice = client.invoices.issue_summary( + invoice_id="invoice_id", + ) + assert_matches_type(InvoiceIssueSummaryResponse, invoice, path=["response"]) + + @parametrize + def test_method_issue_summary_with_all_params(self, client: Orb) -> None: + invoice = client.invoices.issue_summary( + invoice_id="invoice_id", + synchronous=True, + ) + assert_matches_type(InvoiceIssueSummaryResponse, invoice, path=["response"]) + + @parametrize + def test_raw_response_issue_summary(self, client: Orb) -> None: + response = client.invoices.with_raw_response.issue_summary( + invoice_id="invoice_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invoice = response.parse() + assert_matches_type(InvoiceIssueSummaryResponse, invoice, path=["response"]) + + @parametrize + def test_streaming_response_issue_summary(self, client: Orb) -> None: + with client.invoices.with_streaming_response.issue_summary( + invoice_id="invoice_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invoice = response.parse() + assert_matches_type(InvoiceIssueSummaryResponse, invoice, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_issue_summary(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_summary( + invoice_id="", + ) + + @parametrize + def test_method_list_summary(self, client: Orb) -> None: + invoice = client.invoices.list_summary() + assert_matches_type(SyncPage[InvoiceListSummaryResponse], invoice, path=["response"]) + + @parametrize + def test_method_list_summary_with_all_params(self, client: Orb) -> None: + invoice = client.invoices.list_summary( + amount="amount", + amount_gt="amount[gt]", + amount_lt="amount[lt]", + cursor="cursor", + customer_id="customer_id", + date_type="due_date", + due_date=parse_date("2019-12-27"), + due_date_window="due_date_window", + due_date_gt=parse_date("2019-12-27"), + due_date_lt=parse_date("2019-12-27"), + external_customer_id="external_customer_id", + invoice_date_gt=parse_datetime("2019-12-27T18:11:19.117Z"), + invoice_date_gte=parse_datetime("2019-12-27T18:11:19.117Z"), + invoice_date_lt=parse_datetime("2019-12-27T18:11:19.117Z"), + invoice_date_lte=parse_datetime("2019-12-27T18:11:19.117Z"), + is_recurring=True, + limit=1, + status="draft", + subscription_id="subscription_id", + ) + assert_matches_type(SyncPage[InvoiceListSummaryResponse], invoice, path=["response"]) + + @parametrize + def test_raw_response_list_summary(self, client: Orb) -> None: + response = client.invoices.with_raw_response.list_summary() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invoice = response.parse() + assert_matches_type(SyncPage[InvoiceListSummaryResponse], invoice, path=["response"]) + + @parametrize + def test_streaming_response_list_summary(self, client: Orb) -> None: + with client.invoices.with_streaming_response.list_summary() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invoice = response.parse() + assert_matches_type(SyncPage[InvoiceListSummaryResponse], invoice, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_mark_paid(self, client: Orb) -> None: invoice = client.invoices.mark_paid( - "string", + invoice_id="invoice_id", payment_received_date=parse_date("2023-09-22"), ) assert_matches_type(Invoice, invoice, path=["response"]) @@ -358,17 +504,17 @@ def test_method_mark_paid(self, client: Orb) -> None: @parametrize def test_method_mark_paid_with_all_params(self, client: Orb) -> None: invoice = client.invoices.mark_paid( - "string", + invoice_id="invoice_id", payment_received_date=parse_date("2023-09-22"), external_id="external_payment_id_123", - notes="string", + notes="notes", ) assert_matches_type(Invoice, invoice, path=["response"]) @parametrize def test_raw_response_mark_paid(self, client: Orb) -> None: response = client.invoices.with_raw_response.mark_paid( - "string", + invoice_id="invoice_id", payment_received_date=parse_date("2023-09-22"), ) @@ -380,7 +526,7 @@ def test_raw_response_mark_paid(self, client: Orb) -> None: @parametrize def test_streaming_response_mark_paid(self, client: Orb) -> None: with client.invoices.with_streaming_response.mark_paid( - "string", + invoice_id="invoice_id", payment_received_date=parse_date("2023-09-22"), ) as response: assert not response.is_closed @@ -395,21 +541,63 @@ def test_streaming_response_mark_paid(self, client: Orb) -> None: def test_path_params_mark_paid(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.mark_paid( - "", + invoice_id="", payment_received_date=parse_date("2023-09-22"), ) + @parametrize + def test_method_pay(self, client: Orb) -> None: + invoice = client.invoices.pay( + invoice_id="invoice_id", + shared_payment_token_id="shared_payment_token_id", + ) + assert_matches_type(Invoice, invoice, path=["response"]) + + @parametrize + def test_raw_response_pay(self, client: Orb) -> None: + response = client.invoices.with_raw_response.pay( + invoice_id="invoice_id", + shared_payment_token_id="shared_payment_token_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invoice = response.parse() + assert_matches_type(Invoice, invoice, path=["response"]) + + @parametrize + def test_streaming_response_pay(self, client: Orb) -> None: + with client.invoices.with_streaming_response.pay( + invoice_id="invoice_id", + shared_payment_token_id="shared_payment_token_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invoice = response.parse() + assert_matches_type(Invoice, invoice, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_pay(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.pay( + invoice_id="", + shared_payment_token_id="shared_payment_token_id", + ) + @parametrize def test_method_void(self, client: Orb) -> None: invoice = client.invoices.void( - "string", + "invoice_id", ) assert_matches_type(Invoice, invoice, path=["response"]) @parametrize def test_raw_response_void(self, client: Orb) -> None: response = client.invoices.with_raw_response.void( - "string", + "invoice_id", ) assert response.is_closed is True @@ -420,7 +608,7 @@ def test_raw_response_void(self, client: Orb) -> None: @parametrize def test_streaming_response_void(self, client: Orb) -> None: with client.invoices.with_streaming_response.void( - "string", + "invoice_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -439,7 +627,9 @@ def test_path_params_void(self, client: Orb) -> None: class TestAsyncInvoices: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOrb) -> None: @@ -448,34 +638,15 @@ async def test_method_create(self, async_client: AsyncOrb) -> None: invoice_date=parse_datetime("2019-12-27T18:11:19.117Z"), line_items=[ { - "start_date": parse_date("2023-09-22"), "end_date": parse_date("2023-09-22"), - "quantity": 1, - "name": "Line Item Name", "item_id": "4khy3nwzktxv7", "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), - "quantity": 1, "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), "quantity": 1, - "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, + "start_date": parse_date("2023-09-22"), + "unit_config": {"unit_amount": "unit_amount"}, + } ], - net_terms=0, ) assert_matches_type(Invoice, invoice, path=["response"]) @@ -486,38 +657,38 @@ async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> No invoice_date=parse_datetime("2019-12-27T18:11:19.117Z"), line_items=[ { - "start_date": parse_date("2023-09-22"), "end_date": parse_date("2023-09-22"), - "quantity": 1, - "name": "Line Item Name", "item_id": "4khy3nwzktxv7", "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), - "quantity": 1, "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), "quantity": 1, - "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, + "start_date": parse_date("2023-09-22"), + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + } ], - net_terms=0, + auto_collection=True, customer_id="4khy3nwzktxv7", + discount={ + "discount_type": "percentage", + "percentage_discount": 0.15, + "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "reason": "reason", + }, + due_date=parse_date("2025-09-22"), external_customer_id="external-customer-id", memo="An optional memo for my invoice.", metadata={"foo": "string"}, + net_terms=0, will_auto_issue=False, ) assert_matches_type(Invoice, invoice, path=["response"]) @@ -529,34 +700,15 @@ async def test_raw_response_create(self, async_client: AsyncOrb) -> None: invoice_date=parse_datetime("2019-12-27T18:11:19.117Z"), line_items=[ { - "start_date": parse_date("2023-09-22"), "end_date": parse_date("2023-09-22"), - "quantity": 1, - "name": "Line Item Name", "item_id": "4khy3nwzktxv7", "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), - "quantity": 1, "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), "quantity": 1, - "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, + "start_date": parse_date("2023-09-22"), + "unit_config": {"unit_amount": "unit_amount"}, + } ], - net_terms=0, ) assert response.is_closed is True @@ -571,34 +723,58 @@ async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: invoice_date=parse_datetime("2019-12-27T18:11:19.117Z"), line_items=[ { - "start_date": parse_date("2023-09-22"), "end_date": parse_date("2023-09-22"), - "quantity": 1, - "name": "Line Item Name", "item_id": "4khy3nwzktxv7", "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), - "quantity": 1, "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, - { - "start_date": parse_date("2023-09-22"), - "end_date": parse_date("2023-09-22"), "quantity": 1, - "name": "Line Item Name", - "item_id": "4khy3nwzktxv7", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - }, + "start_date": parse_date("2023-09-22"), + "unit_config": {"unit_amount": "unit_amount"}, + } ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invoice = await response.parse() + assert_matches_type(Invoice, invoice, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncOrb) -> None: + invoice = await async_client.invoices.update( + invoice_id="invoice_id", + ) + assert_matches_type(Invoice, invoice, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> None: + invoice = await async_client.invoices.update( + invoice_id="invoice_id", + auto_collection=True, + due_date=parse_date("2023-09-22"), + invoice_date=parse_date("2023-09-22"), + metadata={"foo": "string"}, net_terms=0, + ) + assert_matches_type(Invoice, invoice, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOrb) -> None: + response = await async_client.invoices.with_raw_response.update( + invoice_id="invoice_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invoice = response.parse() + assert_matches_type(Invoice, invoice, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: + async with async_client.invoices.with_streaming_response.update( + invoice_id="invoice_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -608,6 +784,13 @@ async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: assert cast(Any, response.is_closed) is True + @parametrize + async def test_path_params_update(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.update( + invoice_id="", + ) + @parametrize async def test_method_list(self, async_client: AsyncOrb) -> None: invoice = await async_client.invoices.list() @@ -616,25 +799,25 @@ async def test_method_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: invoice = await async_client.invoices.list( - amount="string", - amount_gt="string", - amount_lt="string", - cursor="string", - customer_id="string", + amount="amount", + amount_gt="amount[gt]", + amount_lt="amount[lt]", + cursor="cursor", + customer_id="customer_id", date_type="due_date", due_date=parse_date("2019-12-27"), - due_date_window="string", + due_date_window="due_date_window", due_date_gt=parse_date("2019-12-27"), due_date_lt=parse_date("2019-12-27"), - external_customer_id="string", + external_customer_id="external_customer_id", invoice_date_gt=parse_datetime("2019-12-27T18:11:19.117Z"), invoice_date_gte=parse_datetime("2019-12-27T18:11:19.117Z"), invoice_date_lt=parse_datetime("2019-12-27T18:11:19.117Z"), invoice_date_lte=parse_datetime("2019-12-27T18:11:19.117Z"), is_recurring=True, - limit=0, - status=["draft", "issued", "paid"], - subscription_id="string", + limit=1, + status=["draft"], + subscription_id="subscription_id", ) assert_matches_type(AsyncPage[Invoice], invoice, path=["response"]) @@ -658,17 +841,65 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_delete_line_item(self, async_client: AsyncOrb) -> None: + invoice = await async_client.invoices.delete_line_item( + line_item_id="line_item_id", + invoice_id="invoice_id", + ) + assert invoice is None + + @parametrize + async def test_raw_response_delete_line_item(self, async_client: AsyncOrb) -> None: + response = await async_client.invoices.with_raw_response.delete_line_item( + line_item_id="line_item_id", + invoice_id="invoice_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invoice = response.parse() + assert invoice is None + + @parametrize + async def test_streaming_response_delete_line_item(self, async_client: AsyncOrb) -> None: + async with async_client.invoices.with_streaming_response.delete_line_item( + line_item_id="line_item_id", + invoice_id="invoice_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invoice = await response.parse() + assert invoice is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete_line_item(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.delete_line_item( + line_item_id="line_item_id", + invoice_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `line_item_id` but received ''"): + await async_client.invoices.with_raw_response.delete_line_item( + line_item_id="", + invoice_id="invoice_id", + ) + @parametrize async def test_method_fetch(self, async_client: AsyncOrb) -> None: invoice = await async_client.invoices.fetch( - "string", + "invoice_id", ) assert_matches_type(Invoice, invoice, path=["response"]) @parametrize async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: response = await async_client.invoices.with_raw_response.fetch( - "string", + "invoice_id", ) assert response.is_closed is True @@ -679,7 +910,7 @@ async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_fetch(self, async_client: AsyncOrb) -> None: async with async_client.invoices.with_streaming_response.fetch( - "string", + "invoice_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -698,19 +929,16 @@ 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="string", + subscription_id="subscription_id", ) assert_matches_type(InvoiceFetchUpcomingResponse, invoice, path=["response"]) @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" @@ -719,7 +947,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" @@ -731,14 +961,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( - "string", + 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( - "string", + invoice_id="invoice_id", ) assert response.is_closed is True @@ -749,7 +987,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( - "string", + invoice_id="invoice_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -763,13 +1001,109 @@ 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 + async def test_method_issue_summary(self, async_client: AsyncOrb) -> None: + invoice = await async_client.invoices.issue_summary( + invoice_id="invoice_id", + ) + assert_matches_type(InvoiceIssueSummaryResponse, invoice, path=["response"]) + + @parametrize + async def test_method_issue_summary_with_all_params(self, async_client: AsyncOrb) -> None: + invoice = await async_client.invoices.issue_summary( + invoice_id="invoice_id", + synchronous=True, + ) + assert_matches_type(InvoiceIssueSummaryResponse, invoice, path=["response"]) + + @parametrize + async def test_raw_response_issue_summary(self, async_client: AsyncOrb) -> None: + response = await async_client.invoices.with_raw_response.issue_summary( + invoice_id="invoice_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invoice = response.parse() + assert_matches_type(InvoiceIssueSummaryResponse, invoice, path=["response"]) + + @parametrize + async def test_streaming_response_issue_summary(self, async_client: AsyncOrb) -> None: + async with async_client.invoices.with_streaming_response.issue_summary( + invoice_id="invoice_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invoice = await response.parse() + assert_matches_type(InvoiceIssueSummaryResponse, invoice, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_issue_summary(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_summary( + invoice_id="", + ) + + @parametrize + async def test_method_list_summary(self, async_client: AsyncOrb) -> None: + invoice = await async_client.invoices.list_summary() + assert_matches_type(AsyncPage[InvoiceListSummaryResponse], invoice, path=["response"]) + + @parametrize + async def test_method_list_summary_with_all_params(self, async_client: AsyncOrb) -> None: + invoice = await async_client.invoices.list_summary( + amount="amount", + amount_gt="amount[gt]", + amount_lt="amount[lt]", + cursor="cursor", + customer_id="customer_id", + date_type="due_date", + due_date=parse_date("2019-12-27"), + due_date_window="due_date_window", + due_date_gt=parse_date("2019-12-27"), + due_date_lt=parse_date("2019-12-27"), + external_customer_id="external_customer_id", + invoice_date_gt=parse_datetime("2019-12-27T18:11:19.117Z"), + invoice_date_gte=parse_datetime("2019-12-27T18:11:19.117Z"), + invoice_date_lt=parse_datetime("2019-12-27T18:11:19.117Z"), + invoice_date_lte=parse_datetime("2019-12-27T18:11:19.117Z"), + is_recurring=True, + limit=1, + status="draft", + subscription_id="subscription_id", + ) + assert_matches_type(AsyncPage[InvoiceListSummaryResponse], invoice, path=["response"]) + + @parametrize + async def test_raw_response_list_summary(self, async_client: AsyncOrb) -> None: + response = await async_client.invoices.with_raw_response.list_summary() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invoice = response.parse() + assert_matches_type(AsyncPage[InvoiceListSummaryResponse], invoice, path=["response"]) + + @parametrize + async def test_streaming_response_list_summary(self, async_client: AsyncOrb) -> None: + async with async_client.invoices.with_streaming_response.list_summary() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invoice = await response.parse() + assert_matches_type(AsyncPage[InvoiceListSummaryResponse], invoice, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_mark_paid(self, async_client: AsyncOrb) -> None: invoice = await async_client.invoices.mark_paid( - "string", + invoice_id="invoice_id", payment_received_date=parse_date("2023-09-22"), ) assert_matches_type(Invoice, invoice, path=["response"]) @@ -777,17 +1111,17 @@ async def test_method_mark_paid(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_mark_paid_with_all_params(self, async_client: AsyncOrb) -> None: invoice = await async_client.invoices.mark_paid( - "string", + invoice_id="invoice_id", payment_received_date=parse_date("2023-09-22"), external_id="external_payment_id_123", - notes="string", + notes="notes", ) assert_matches_type(Invoice, invoice, path=["response"]) @parametrize async def test_raw_response_mark_paid(self, async_client: AsyncOrb) -> None: response = await async_client.invoices.with_raw_response.mark_paid( - "string", + invoice_id="invoice_id", payment_received_date=parse_date("2023-09-22"), ) @@ -799,7 +1133,7 @@ async def test_raw_response_mark_paid(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_mark_paid(self, async_client: AsyncOrb) -> None: async with async_client.invoices.with_streaming_response.mark_paid( - "string", + invoice_id="invoice_id", payment_received_date=parse_date("2023-09-22"), ) as response: assert not response.is_closed @@ -814,21 +1148,63 @@ async def test_streaming_response_mark_paid(self, async_client: AsyncOrb) -> Non async def test_path_params_mark_paid(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.mark_paid( - "", + invoice_id="", payment_received_date=parse_date("2023-09-22"), ) + @parametrize + async def test_method_pay(self, async_client: AsyncOrb) -> None: + invoice = await async_client.invoices.pay( + invoice_id="invoice_id", + shared_payment_token_id="shared_payment_token_id", + ) + assert_matches_type(Invoice, invoice, path=["response"]) + + @parametrize + async def test_raw_response_pay(self, async_client: AsyncOrb) -> None: + response = await async_client.invoices.with_raw_response.pay( + invoice_id="invoice_id", + shared_payment_token_id="shared_payment_token_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invoice = response.parse() + assert_matches_type(Invoice, invoice, path=["response"]) + + @parametrize + async def test_streaming_response_pay(self, async_client: AsyncOrb) -> None: + async with async_client.invoices.with_streaming_response.pay( + invoice_id="invoice_id", + shared_payment_token_id="shared_payment_token_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invoice = await response.parse() + assert_matches_type(Invoice, invoice, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_pay(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.pay( + invoice_id="", + shared_payment_token_id="shared_payment_token_id", + ) + @parametrize async def test_method_void(self, async_client: AsyncOrb) -> None: invoice = await async_client.invoices.void( - "string", + "invoice_id", ) assert_matches_type(Invoice, invoice, path=["response"]) @parametrize async def test_raw_response_void(self, async_client: AsyncOrb) -> None: response = await async_client.invoices.with_raw_response.void( - "string", + "invoice_id", ) assert response.is_closed is True @@ -839,7 +1215,7 @@ async def test_raw_response_void(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_void(self, async_client: AsyncOrb) -> None: async with async_client.invoices.with_streaming_response.void( - "string", + "invoice_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/test_items.py b/tests/api_resources/test_items.py index 68f4c084..220d2c17 100644 --- a/tests/api_resources/test_items.py +++ b/tests/api_resources/test_items.py @@ -25,6 +25,14 @@ def test_method_create(self, client: Orb) -> None: ) assert_matches_type(Item, item, path=["response"]) + @parametrize + def test_method_create_with_all_params(self, client: Orb) -> None: + item = client.items.create( + name="API requests", + metadata={"foo": "string"}, + ) + assert_matches_type(Item, item, path=["response"]) + @parametrize def test_raw_response_create(self, client: Orb) -> None: response = client.items.with_raw_response.create( @@ -49,6 +57,59 @@ def test_streaming_response_create(self, client: Orb) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_update(self, client: Orb) -> None: + item = client.items.update( + item_id="item_id", + ) + assert_matches_type(Item, item, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Orb) -> None: + item = client.items.update( + item_id="item_id", + external_connections=[ + { + "external_connection_name": "stripe", + "external_entity_id": "external_entity_id", + } + ], + metadata={"foo": "string"}, + name="name", + ) + assert_matches_type(Item, item, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Orb) -> None: + response = client.items.with_raw_response.update( + item_id="item_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(Item, item, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Orb) -> None: + with client.items.with_streaming_response.update( + item_id="item_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = response.parse() + assert_matches_type(Item, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `item_id` but received ''"): + client.items.with_raw_response.update( + item_id="", + ) + @parametrize def test_method_list(self, client: Orb) -> None: item = client.items.list() @@ -57,8 +118,8 @@ def test_method_list(self, client: Orb) -> None: @parametrize def test_method_list_with_all_params(self, client: Orb) -> None: item = client.items.list( - cursor="string", - limit=0, + cursor="cursor", + limit=1, ) assert_matches_type(SyncPage[Item], item, path=["response"]) @@ -82,17 +143,55 @@ def test_streaming_response_list(self, client: Orb) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_archive(self, client: Orb) -> None: + item = client.items.archive( + "item_id", + ) + assert_matches_type(Item, item, path=["response"]) + + @parametrize + def test_raw_response_archive(self, client: Orb) -> None: + response = client.items.with_raw_response.archive( + "item_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(Item, item, path=["response"]) + + @parametrize + def test_streaming_response_archive(self, client: Orb) -> None: + with client.items.with_streaming_response.archive( + "item_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = response.parse() + assert_matches_type(Item, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_archive(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `item_id` but received ''"): + client.items.with_raw_response.archive( + "", + ) + @parametrize def test_method_fetch(self, client: Orb) -> None: item = client.items.fetch( - "string", + "item_id", ) assert_matches_type(Item, item, path=["response"]) @parametrize def test_raw_response_fetch(self, client: Orb) -> None: response = client.items.with_raw_response.fetch( - "string", + "item_id", ) assert response.is_closed is True @@ -103,7 +202,7 @@ def test_raw_response_fetch(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch(self, client: Orb) -> None: with client.items.with_streaming_response.fetch( - "string", + "item_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -122,7 +221,9 @@ def test_path_params_fetch(self, client: Orb) -> None: class TestAsyncItems: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOrb) -> None: @@ -131,6 +232,14 @@ async def test_method_create(self, async_client: AsyncOrb) -> None: ) assert_matches_type(Item, item, path=["response"]) + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> None: + item = await async_client.items.create( + name="API requests", + metadata={"foo": "string"}, + ) + assert_matches_type(Item, item, path=["response"]) + @parametrize async def test_raw_response_create(self, async_client: AsyncOrb) -> None: response = await async_client.items.with_raw_response.create( @@ -155,6 +264,59 @@ async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_update(self, async_client: AsyncOrb) -> None: + item = await async_client.items.update( + item_id="item_id", + ) + assert_matches_type(Item, item, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> None: + item = await async_client.items.update( + item_id="item_id", + external_connections=[ + { + "external_connection_name": "stripe", + "external_entity_id": "external_entity_id", + } + ], + metadata={"foo": "string"}, + name="name", + ) + assert_matches_type(Item, item, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOrb) -> None: + response = await async_client.items.with_raw_response.update( + item_id="item_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(Item, item, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: + async with async_client.items.with_streaming_response.update( + item_id="item_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = await response.parse() + assert_matches_type(Item, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `item_id` but received ''"): + await async_client.items.with_raw_response.update( + item_id="", + ) + @parametrize async def test_method_list(self, async_client: AsyncOrb) -> None: item = await async_client.items.list() @@ -163,8 +325,8 @@ async def test_method_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: item = await async_client.items.list( - cursor="string", - limit=0, + cursor="cursor", + limit=1, ) assert_matches_type(AsyncPage[Item], item, path=["response"]) @@ -188,17 +350,55 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_archive(self, async_client: AsyncOrb) -> None: + item = await async_client.items.archive( + "item_id", + ) + assert_matches_type(Item, item, path=["response"]) + + @parametrize + async def test_raw_response_archive(self, async_client: AsyncOrb) -> None: + response = await async_client.items.with_raw_response.archive( + "item_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(Item, item, path=["response"]) + + @parametrize + async def test_streaming_response_archive(self, async_client: AsyncOrb) -> None: + async with async_client.items.with_streaming_response.archive( + "item_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = await response.parse() + assert_matches_type(Item, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_archive(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `item_id` but received ''"): + await async_client.items.with_raw_response.archive( + "", + ) + @parametrize async def test_method_fetch(self, async_client: AsyncOrb) -> None: item = await async_client.items.fetch( - "string", + "item_id", ) assert_matches_type(Item, item, path=["response"]) @parametrize async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: response = await async_client.items.with_raw_response.fetch( - "string", + "item_id", ) assert response.is_closed is True @@ -209,7 +409,7 @@ async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_fetch(self, async_client: AsyncOrb) -> None: async with async_client.items.with_streaming_response.fetch( - "string", + "item_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/test_license_types.py b/tests/api_resources/test_license_types.py new file mode 100644 index 00000000..804081fe --- /dev/null +++ b/tests/api_resources/test_license_types.py @@ -0,0 +1,239 @@ +# 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.types import ( + LicenseTypeListResponse, + LicenseTypeCreateResponse, + LicenseTypeRetrieveResponse, +) +from tests.utils import assert_matches_type +from orb.pagination import SyncPage, AsyncPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestLicenseTypes: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Orb) -> None: + license_type = client.license_types.create( + grouping_key="x", + name="x", + ) + assert_matches_type(LicenseTypeCreateResponse, license_type, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Orb) -> None: + response = client.license_types.with_raw_response.create( + grouping_key="x", + name="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license_type = response.parse() + assert_matches_type(LicenseTypeCreateResponse, license_type, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Orb) -> None: + with client.license_types.with_streaming_response.create( + grouping_key="x", + name="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license_type = response.parse() + assert_matches_type(LicenseTypeCreateResponse, license_type, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: Orb) -> None: + license_type = client.license_types.retrieve( + "license_type_id", + ) + assert_matches_type(LicenseTypeRetrieveResponse, license_type, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: Orb) -> None: + response = client.license_types.with_raw_response.retrieve( + "license_type_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license_type = response.parse() + assert_matches_type(LicenseTypeRetrieveResponse, license_type, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: Orb) -> None: + with client.license_types.with_streaming_response.retrieve( + "license_type_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license_type = response.parse() + assert_matches_type(LicenseTypeRetrieveResponse, license_type, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `license_type_id` but received ''"): + client.license_types.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_list(self, client: Orb) -> None: + license_type = client.license_types.list() + assert_matches_type(SyncPage[LicenseTypeListResponse], license_type, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Orb) -> None: + license_type = client.license_types.list( + cursor="cursor", + limit=1, + ) + assert_matches_type(SyncPage[LicenseTypeListResponse], license_type, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Orb) -> None: + response = client.license_types.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license_type = response.parse() + assert_matches_type(SyncPage[LicenseTypeListResponse], license_type, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Orb) -> None: + with client.license_types.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license_type = response.parse() + assert_matches_type(SyncPage[LicenseTypeListResponse], license_type, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncLicenseTypes: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOrb) -> None: + license_type = await async_client.license_types.create( + grouping_key="x", + name="x", + ) + assert_matches_type(LicenseTypeCreateResponse, license_type, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOrb) -> None: + response = await async_client.license_types.with_raw_response.create( + grouping_key="x", + name="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license_type = response.parse() + assert_matches_type(LicenseTypeCreateResponse, license_type, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: + async with async_client.license_types.with_streaming_response.create( + grouping_key="x", + name="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license_type = await response.parse() + assert_matches_type(LicenseTypeCreateResponse, license_type, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOrb) -> None: + license_type = await async_client.license_types.retrieve( + "license_type_id", + ) + assert_matches_type(LicenseTypeRetrieveResponse, license_type, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOrb) -> None: + response = await async_client.license_types.with_raw_response.retrieve( + "license_type_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license_type = response.parse() + assert_matches_type(LicenseTypeRetrieveResponse, license_type, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOrb) -> None: + async with async_client.license_types.with_streaming_response.retrieve( + "license_type_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license_type = await response.parse() + assert_matches_type(LicenseTypeRetrieveResponse, license_type, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `license_type_id` but received ''"): + await async_client.license_types.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOrb) -> None: + license_type = await async_client.license_types.list() + assert_matches_type(AsyncPage[LicenseTypeListResponse], license_type, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: + license_type = await async_client.license_types.list( + cursor="cursor", + limit=1, + ) + assert_matches_type(AsyncPage[LicenseTypeListResponse], license_type, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOrb) -> None: + response = await async_client.license_types.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license_type = response.parse() + assert_matches_type(AsyncPage[LicenseTypeListResponse], license_type, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: + async with async_client.license_types.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license_type = await response.parse() + assert_matches_type(AsyncPage[LicenseTypeListResponse], license_type, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_licenses.py b/tests/api_resources/test_licenses.py new file mode 100644 index 00000000..a3afcf49 --- /dev/null +++ b/tests/api_resources/test_licenses.py @@ -0,0 +1,474 @@ +# 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.types import ( + LicenseListResponse, + LicenseCreateResponse, + LicenseRetrieveResponse, + LicenseDeactivateResponse, + LicenseRetrieveByExternalIDResponse, +) +from orb._utils import parse_date +from tests.utils import assert_matches_type +from orb.pagination import SyncPage, AsyncPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestLicenses: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Orb) -> None: + license = client.licenses.create( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + assert_matches_type(LicenseCreateResponse, license, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Orb) -> None: + license = client.licenses.create( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + end_date=parse_date("2026-01-27"), + start_date=parse_date("2026-01-27"), + ) + assert_matches_type(LicenseCreateResponse, license, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Orb) -> None: + response = client.licenses.with_raw_response.create( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license = response.parse() + assert_matches_type(LicenseCreateResponse, license, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Orb) -> None: + with client.licenses.with_streaming_response.create( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license = response.parse() + assert_matches_type(LicenseCreateResponse, license, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: Orb) -> None: + license = client.licenses.retrieve( + "license_id", + ) + assert_matches_type(LicenseRetrieveResponse, license, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: Orb) -> None: + response = client.licenses.with_raw_response.retrieve( + "license_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license = response.parse() + assert_matches_type(LicenseRetrieveResponse, license, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: Orb) -> None: + with client.licenses.with_streaming_response.retrieve( + "license_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license = response.parse() + assert_matches_type(LicenseRetrieveResponse, license, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `license_id` but received ''"): + client.licenses.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_list(self, client: Orb) -> None: + license = client.licenses.list( + subscription_id="subscription_id", + ) + assert_matches_type(SyncPage[LicenseListResponse], license, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Orb) -> None: + license = client.licenses.list( + subscription_id="subscription_id", + cursor="cursor", + external_license_id="external_license_id", + license_type_id="license_type_id", + limit=1, + status="active", + ) + assert_matches_type(SyncPage[LicenseListResponse], license, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Orb) -> None: + response = client.licenses.with_raw_response.list( + subscription_id="subscription_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license = response.parse() + assert_matches_type(SyncPage[LicenseListResponse], license, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Orb) -> None: + with client.licenses.with_streaming_response.list( + subscription_id="subscription_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license = response.parse() + assert_matches_type(SyncPage[LicenseListResponse], license, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_deactivate(self, client: Orb) -> None: + license = client.licenses.deactivate( + license_id="license_id", + ) + assert_matches_type(LicenseDeactivateResponse, license, path=["response"]) + + @parametrize + def test_method_deactivate_with_all_params(self, client: Orb) -> None: + license = client.licenses.deactivate( + license_id="license_id", + end_date=parse_date("2026-01-27"), + ) + assert_matches_type(LicenseDeactivateResponse, license, path=["response"]) + + @parametrize + def test_raw_response_deactivate(self, client: Orb) -> None: + response = client.licenses.with_raw_response.deactivate( + license_id="license_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license = response.parse() + assert_matches_type(LicenseDeactivateResponse, license, path=["response"]) + + @parametrize + def test_streaming_response_deactivate(self, client: Orb) -> None: + with client.licenses.with_streaming_response.deactivate( + license_id="license_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license = response.parse() + assert_matches_type(LicenseDeactivateResponse, license, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_deactivate(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `license_id` but received ''"): + client.licenses.with_raw_response.deactivate( + license_id="", + ) + + @parametrize + def test_method_retrieve_by_external_id(self, client: Orb) -> None: + license = client.licenses.retrieve_by_external_id( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + assert_matches_type(LicenseRetrieveByExternalIDResponse, license, path=["response"]) + + @parametrize + def test_raw_response_retrieve_by_external_id(self, client: Orb) -> None: + response = client.licenses.with_raw_response.retrieve_by_external_id( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license = response.parse() + assert_matches_type(LicenseRetrieveByExternalIDResponse, license, path=["response"]) + + @parametrize + def test_streaming_response_retrieve_by_external_id(self, client: Orb) -> None: + with client.licenses.with_streaming_response.retrieve_by_external_id( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license = response.parse() + assert_matches_type(LicenseRetrieveByExternalIDResponse, license, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve_by_external_id(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_license_id` but received ''"): + client.licenses.with_raw_response.retrieve_by_external_id( + external_license_id="", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + + +class TestAsyncLicenses: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncOrb) -> None: + license = await async_client.licenses.create( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + assert_matches_type(LicenseCreateResponse, license, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> None: + license = await async_client.licenses.create( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + end_date=parse_date("2026-01-27"), + start_date=parse_date("2026-01-27"), + ) + assert_matches_type(LicenseCreateResponse, license, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOrb) -> None: + response = await async_client.licenses.with_raw_response.create( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license = response.parse() + assert_matches_type(LicenseCreateResponse, license, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: + async with async_client.licenses.with_streaming_response.create( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license = await response.parse() + assert_matches_type(LicenseCreateResponse, license, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOrb) -> None: + license = await async_client.licenses.retrieve( + "license_id", + ) + assert_matches_type(LicenseRetrieveResponse, license, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOrb) -> None: + response = await async_client.licenses.with_raw_response.retrieve( + "license_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license = response.parse() + assert_matches_type(LicenseRetrieveResponse, license, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOrb) -> None: + async with async_client.licenses.with_streaming_response.retrieve( + "license_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license = await response.parse() + assert_matches_type(LicenseRetrieveResponse, license, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `license_id` but received ''"): + await async_client.licenses.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOrb) -> None: + license = await async_client.licenses.list( + subscription_id="subscription_id", + ) + assert_matches_type(AsyncPage[LicenseListResponse], license, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: + license = await async_client.licenses.list( + subscription_id="subscription_id", + cursor="cursor", + external_license_id="external_license_id", + license_type_id="license_type_id", + limit=1, + status="active", + ) + assert_matches_type(AsyncPage[LicenseListResponse], license, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOrb) -> None: + response = await async_client.licenses.with_raw_response.list( + subscription_id="subscription_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license = response.parse() + assert_matches_type(AsyncPage[LicenseListResponse], license, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: + async with async_client.licenses.with_streaming_response.list( + subscription_id="subscription_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license = await response.parse() + assert_matches_type(AsyncPage[LicenseListResponse], license, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_deactivate(self, async_client: AsyncOrb) -> None: + license = await async_client.licenses.deactivate( + license_id="license_id", + ) + assert_matches_type(LicenseDeactivateResponse, license, path=["response"]) + + @parametrize + async def test_method_deactivate_with_all_params(self, async_client: AsyncOrb) -> None: + license = await async_client.licenses.deactivate( + license_id="license_id", + end_date=parse_date("2026-01-27"), + ) + assert_matches_type(LicenseDeactivateResponse, license, path=["response"]) + + @parametrize + async def test_raw_response_deactivate(self, async_client: AsyncOrb) -> None: + response = await async_client.licenses.with_raw_response.deactivate( + license_id="license_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license = response.parse() + assert_matches_type(LicenseDeactivateResponse, license, path=["response"]) + + @parametrize + async def test_streaming_response_deactivate(self, async_client: AsyncOrb) -> None: + async with async_client.licenses.with_streaming_response.deactivate( + license_id="license_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license = await response.parse() + assert_matches_type(LicenseDeactivateResponse, license, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_deactivate(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `license_id` but received ''"): + await async_client.licenses.with_raw_response.deactivate( + license_id="", + ) + + @parametrize + async def test_method_retrieve_by_external_id(self, async_client: AsyncOrb) -> None: + license = await async_client.licenses.retrieve_by_external_id( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + assert_matches_type(LicenseRetrieveByExternalIDResponse, license, path=["response"]) + + @parametrize + async def test_raw_response_retrieve_by_external_id(self, async_client: AsyncOrb) -> None: + response = await async_client.licenses.with_raw_response.retrieve_by_external_id( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + license = response.parse() + assert_matches_type(LicenseRetrieveByExternalIDResponse, license, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve_by_external_id(self, async_client: AsyncOrb) -> None: + async with async_client.licenses.with_streaming_response.retrieve_by_external_id( + external_license_id="external_license_id", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + license = await response.parse() + assert_matches_type(LicenseRetrieveByExternalIDResponse, license, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve_by_external_id(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `external_license_id` but received ''"): + await async_client.licenses.with_raw_response.retrieve_by_external_id( + external_license_id="", + license_type_id="license_type_id", + subscription_id="subscription_id", + ) diff --git a/tests/api_resources/test_metrics.py b/tests/api_resources/test_metrics.py index a75b819e..5b58742a 100644 --- a/tests/api_resources/test_metrics.py +++ b/tests/api_resources/test_metrics.py @@ -8,11 +8,7 @@ import pytest from orb import Orb, AsyncOrb -from orb.types import ( - MetricListResponse, - MetricFetchResponse, - MetricCreateResponse, -) +from orb.types import BillableMetric from orb._utils import parse_datetime from tests.utils import assert_matches_type from orb.pagination import SyncPage, AsyncPage @@ -27,28 +23,28 @@ class TestMetrics: def test_method_create(self, client: Orb) -> None: metric = client.metrics.create( description="Sum of bytes downloaded in fast mode", - item_id="string", + item_id="item_id", name="Bytes downloaded", sql="SELECT sum(bytes_downloaded) FROM events WHERE download_speed = 'fast'", ) - assert_matches_type(MetricCreateResponse, metric, path=["response"]) + assert_matches_type(BillableMetric, metric, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: Orb) -> None: metric = client.metrics.create( description="Sum of bytes downloaded in fast mode", - item_id="string", + item_id="item_id", name="Bytes downloaded", sql="SELECT sum(bytes_downloaded) FROM events WHERE download_speed = 'fast'", metadata={"foo": "string"}, ) - assert_matches_type(MetricCreateResponse, metric, path=["response"]) + assert_matches_type(BillableMetric, metric, path=["response"]) @parametrize def test_raw_response_create(self, client: Orb) -> None: response = client.metrics.with_raw_response.create( description="Sum of bytes downloaded in fast mode", - item_id="string", + item_id="item_id", name="Bytes downloaded", sql="SELECT sum(bytes_downloaded) FROM events WHERE download_speed = 'fast'", ) @@ -56,13 +52,13 @@ 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" metric = response.parse() - assert_matches_type(MetricCreateResponse, metric, path=["response"]) + assert_matches_type(BillableMetric, metric, path=["response"]) @parametrize def test_streaming_response_create(self, client: Orb) -> None: with client.metrics.with_streaming_response.create( description="Sum of bytes downloaded in fast mode", - item_id="string", + item_id="item_id", name="Bytes downloaded", sql="SELECT sum(bytes_downloaded) FROM events WHERE download_speed = 'fast'", ) as response: @@ -70,14 +66,60 @@ def test_streaming_response_create(self, client: Orb) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" metric = response.parse() - assert_matches_type(MetricCreateResponse, metric, path=["response"]) + assert_matches_type(BillableMetric, metric, path=["response"]) assert cast(Any, response.is_closed) is True + @parametrize + def test_method_update(self, client: Orb) -> None: + metric = client.metrics.update( + metric_id="metric_id", + ) + assert_matches_type(BillableMetric, metric, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Orb) -> None: + metric = client.metrics.update( + metric_id="metric_id", + metadata={"foo": "string"}, + ) + assert_matches_type(BillableMetric, metric, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Orb) -> None: + response = client.metrics.with_raw_response.update( + metric_id="metric_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + metric = response.parse() + assert_matches_type(BillableMetric, metric, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Orb) -> None: + with client.metrics.with_streaming_response.update( + metric_id="metric_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + metric = response.parse() + assert_matches_type(BillableMetric, metric, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `metric_id` but received ''"): + client.metrics.with_raw_response.update( + metric_id="", + ) + @parametrize def test_method_list(self, client: Orb) -> None: metric = client.metrics.list() - assert_matches_type(SyncPage[MetricListResponse], metric, path=["response"]) + assert_matches_type(SyncPage[BillableMetric], metric, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: Orb) -> None: @@ -86,10 +128,10 @@ def test_method_list_with_all_params(self, client: Orb) -> None: created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), - cursor="string", - limit=0, + cursor="cursor", + limit=1, ) - assert_matches_type(SyncPage[MetricListResponse], metric, path=["response"]) + assert_matches_type(SyncPage[BillableMetric], metric, path=["response"]) @parametrize def test_raw_response_list(self, client: Orb) -> None: @@ -98,7 +140,7 @@ def test_raw_response_list(self, client: Orb) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" metric = response.parse() - assert_matches_type(SyncPage[MetricListResponse], metric, path=["response"]) + assert_matches_type(SyncPage[BillableMetric], metric, path=["response"]) @parametrize def test_streaming_response_list(self, client: Orb) -> None: @@ -107,38 +149,38 @@ def test_streaming_response_list(self, client: Orb) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" metric = response.parse() - assert_matches_type(SyncPage[MetricListResponse], metric, path=["response"]) + assert_matches_type(SyncPage[BillableMetric], metric, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_method_fetch(self, client: Orb) -> None: metric = client.metrics.fetch( - "string", + "metric_id", ) - assert_matches_type(MetricFetchResponse, metric, path=["response"]) + assert_matches_type(BillableMetric, metric, path=["response"]) @parametrize def test_raw_response_fetch(self, client: Orb) -> None: response = client.metrics.with_raw_response.fetch( - "string", + "metric_id", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" metric = response.parse() - assert_matches_type(MetricFetchResponse, metric, path=["response"]) + assert_matches_type(BillableMetric, metric, path=["response"]) @parametrize def test_streaming_response_fetch(self, client: Orb) -> None: with client.metrics.with_streaming_response.fetch( - "string", + "metric_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" metric = response.parse() - assert_matches_type(MetricFetchResponse, metric, path=["response"]) + assert_matches_type(BillableMetric, metric, path=["response"]) assert cast(Any, response.is_closed) is True @@ -151,34 +193,36 @@ def test_path_params_fetch(self, client: Orb) -> None: class TestAsyncMetrics: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOrb) -> None: metric = await async_client.metrics.create( description="Sum of bytes downloaded in fast mode", - item_id="string", + item_id="item_id", name="Bytes downloaded", sql="SELECT sum(bytes_downloaded) FROM events WHERE download_speed = 'fast'", ) - assert_matches_type(MetricCreateResponse, metric, path=["response"]) + assert_matches_type(BillableMetric, metric, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> None: metric = await async_client.metrics.create( description="Sum of bytes downloaded in fast mode", - item_id="string", + item_id="item_id", name="Bytes downloaded", sql="SELECT sum(bytes_downloaded) FROM events WHERE download_speed = 'fast'", metadata={"foo": "string"}, ) - assert_matches_type(MetricCreateResponse, metric, path=["response"]) + assert_matches_type(BillableMetric, metric, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncOrb) -> None: response = await async_client.metrics.with_raw_response.create( description="Sum of bytes downloaded in fast mode", - item_id="string", + item_id="item_id", name="Bytes downloaded", sql="SELECT sum(bytes_downloaded) FROM events WHERE download_speed = 'fast'", ) @@ -186,13 +230,13 @@ 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" metric = response.parse() - assert_matches_type(MetricCreateResponse, metric, path=["response"]) + assert_matches_type(BillableMetric, metric, path=["response"]) @parametrize async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: async with async_client.metrics.with_streaming_response.create( description="Sum of bytes downloaded in fast mode", - item_id="string", + item_id="item_id", name="Bytes downloaded", sql="SELECT sum(bytes_downloaded) FROM events WHERE download_speed = 'fast'", ) as response: @@ -200,14 +244,60 @@ async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" metric = await response.parse() - assert_matches_type(MetricCreateResponse, metric, path=["response"]) + assert_matches_type(BillableMetric, metric, path=["response"]) assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_update(self, async_client: AsyncOrb) -> None: + metric = await async_client.metrics.update( + metric_id="metric_id", + ) + assert_matches_type(BillableMetric, metric, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> None: + metric = await async_client.metrics.update( + metric_id="metric_id", + metadata={"foo": "string"}, + ) + assert_matches_type(BillableMetric, metric, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOrb) -> None: + response = await async_client.metrics.with_raw_response.update( + metric_id="metric_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + metric = response.parse() + assert_matches_type(BillableMetric, metric, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: + async with async_client.metrics.with_streaming_response.update( + metric_id="metric_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + metric = await response.parse() + assert_matches_type(BillableMetric, metric, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `metric_id` but received ''"): + await async_client.metrics.with_raw_response.update( + metric_id="", + ) + @parametrize async def test_method_list(self, async_client: AsyncOrb) -> None: metric = await async_client.metrics.list() - assert_matches_type(AsyncPage[MetricListResponse], metric, path=["response"]) + assert_matches_type(AsyncPage[BillableMetric], metric, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: @@ -216,10 +306,10 @@ async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), - cursor="string", - limit=0, + cursor="cursor", + limit=1, ) - assert_matches_type(AsyncPage[MetricListResponse], metric, path=["response"]) + assert_matches_type(AsyncPage[BillableMetric], metric, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncOrb) -> None: @@ -228,7 +318,7 @@ async def test_raw_response_list(self, async_client: AsyncOrb) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" metric = response.parse() - assert_matches_type(AsyncPage[MetricListResponse], metric, path=["response"]) + assert_matches_type(AsyncPage[BillableMetric], metric, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: @@ -237,38 +327,38 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" metric = await response.parse() - assert_matches_type(AsyncPage[MetricListResponse], metric, path=["response"]) + assert_matches_type(AsyncPage[BillableMetric], metric, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_method_fetch(self, async_client: AsyncOrb) -> None: metric = await async_client.metrics.fetch( - "string", + "metric_id", ) - assert_matches_type(MetricFetchResponse, metric, path=["response"]) + assert_matches_type(BillableMetric, metric, path=["response"]) @parametrize async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: response = await async_client.metrics.with_raw_response.fetch( - "string", + "metric_id", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" metric = response.parse() - assert_matches_type(MetricFetchResponse, metric, path=["response"]) + assert_matches_type(BillableMetric, metric, path=["response"]) @parametrize async def test_streaming_response_fetch(self, async_client: AsyncOrb) -> None: async with async_client.metrics.with_streaming_response.fetch( - "string", + "metric_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" metric = await response.parse() - assert_matches_type(MetricFetchResponse, metric, path=["response"]) + assert_matches_type(BillableMetric, metric, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_plans.py b/tests/api_resources/test_plans.py index ea779b35..b8867eb5 100644 --- a/tests/api_resources/test_plans.py +++ b/tests/api_resources/test_plans.py @@ -22,60 +22,169 @@ class TestPlans: @parametrize def test_method_create(self, client: Orb) -> None: plan = client.plans.create( - currency="string", - name="string", - prices=[ - { - "name": "Annual fee", - "item_id": "string", - "cadence": "annual", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - } - ], + currency="currency", + name="name", + prices=[{}], ) assert_matches_type(Plan, plan, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: Orb) -> None: plan = client.plans.create( - currency="string", - name="string", + currency="currency", + name="name", prices=[ { - "external_price_id": "string", - "name": "Annual fee", - "billable_metric_id": "string", - "item_id": "string", - "billed_in_advance": True, - "fixed_price_quantity": 0, - "invoice_grouping_key": "string", - "cadence": "annual", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "license_allocation_price": { + "cadence": "annual", + "item_id": "item_id", + "license_allocations": [ + { + "amount": "amount", + "currency": "currency", + "write_off_overage": True, + } + ], + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "plan_phase_order": 0, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + } + ], + adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "plan_phase_order": 0, } ], - default_invoice_memo="string", - external_plan_id="string", + default_invoice_memo="default_invoice_memo", + description="description", + external_plan_id="external_plan_id", metadata={"foo": "string"}, net_terms=0, + plan_phases=[ + { + "order": 0, + "align_billing_with_phase_start_date": True, + "duration": 1, + "duration_unit": "daily", + } + ], + status="active", ) assert_matches_type(Plan, plan, path=["response"]) @parametrize def test_raw_response_create(self, client: Orb) -> None: response = client.plans.with_raw_response.create( - currency="string", - name="string", - prices=[ - { - "name": "Annual fee", - "item_id": "string", - "cadence": "annual", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - } - ], + currency="currency", + name="name", + prices=[{}], ) assert response.is_closed is True @@ -86,17 +195,9 @@ def test_raw_response_create(self, client: Orb) -> None: @parametrize def test_streaming_response_create(self, client: Orb) -> None: with client.plans.with_streaming_response.create( - currency="string", - name="string", - prices=[ - { - "name": "Annual fee", - "item_id": "string", - "cadence": "annual", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - } - ], + currency="currency", + name="name", + prices=[{}], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -109,15 +210,16 @@ def test_streaming_response_create(self, client: Orb) -> None: @parametrize def test_method_update(self, client: Orb) -> None: plan = client.plans.update( - "string", + plan_id="plan_id", ) assert_matches_type(Plan, plan, path=["response"]) @parametrize def test_method_update_with_all_params(self, client: Orb) -> None: plan = client.plans.update( - "string", - external_plan_id="string", + plan_id="plan_id", + description="description", + external_plan_id="external_plan_id", metadata={"foo": "string"}, ) assert_matches_type(Plan, plan, path=["response"]) @@ -125,7 +227,7 @@ def test_method_update_with_all_params(self, client: Orb) -> None: @parametrize def test_raw_response_update(self, client: Orb) -> None: response = client.plans.with_raw_response.update( - "string", + plan_id="plan_id", ) assert response.is_closed is True @@ -136,7 +238,7 @@ def test_raw_response_update(self, client: Orb) -> None: @parametrize def test_streaming_response_update(self, client: Orb) -> None: with client.plans.with_streaming_response.update( - "string", + plan_id="plan_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -150,7 +252,7 @@ def test_streaming_response_update(self, client: Orb) -> None: def test_path_params_update(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): client.plans.with_raw_response.update( - "", + plan_id="", ) @parametrize @@ -165,8 +267,8 @@ def test_method_list_with_all_params(self, client: Orb) -> None: created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), - cursor="string", - limit=0, + cursor="cursor", + limit=1, status="active", ) assert_matches_type(SyncPage[Plan], plan, path=["response"]) @@ -194,14 +296,14 @@ def test_streaming_response_list(self, client: Orb) -> None: @parametrize def test_method_fetch(self, client: Orb) -> None: plan = client.plans.fetch( - "string", + "plan_id", ) assert_matches_type(Plan, plan, path=["response"]) @parametrize def test_raw_response_fetch(self, client: Orb) -> None: response = client.plans.with_raw_response.fetch( - "string", + "plan_id", ) assert response.is_closed is True @@ -212,7 +314,7 @@ def test_raw_response_fetch(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch(self, client: Orb) -> None: with client.plans.with_streaming_response.fetch( - "string", + "plan_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -231,65 +333,176 @@ def test_path_params_fetch(self, client: Orb) -> None: class TestAsyncPlans: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create(self, async_client: AsyncOrb) -> None: plan = await async_client.plans.create( - currency="string", - name="string", - prices=[ - { - "name": "Annual fee", - "item_id": "string", - "cadence": "annual", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - } - ], + currency="currency", + name="name", + prices=[{}], ) assert_matches_type(Plan, plan, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> None: plan = await async_client.plans.create( - currency="string", - name="string", + currency="currency", + name="name", prices=[ { - "external_price_id": "string", - "name": "Annual fee", - "billable_metric_id": "string", - "item_id": "string", - "billed_in_advance": True, - "fixed_price_quantity": 0, - "invoice_grouping_key": "string", - "cadence": "annual", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "license_allocation_price": { + "cadence": "annual", + "item_id": "item_id", + "license_allocations": [ + { + "amount": "amount", + "currency": "currency", + "write_off_overage": True, + } + ], + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "plan_phase_order": 0, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + } + ], + adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "plan_phase_order": 0, } ], - default_invoice_memo="string", - external_plan_id="string", + default_invoice_memo="default_invoice_memo", + description="description", + external_plan_id="external_plan_id", metadata={"foo": "string"}, net_terms=0, + plan_phases=[ + { + "order": 0, + "align_billing_with_phase_start_date": True, + "duration": 1, + "duration_unit": "daily", + } + ], + status="active", ) assert_matches_type(Plan, plan, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncOrb) -> None: response = await async_client.plans.with_raw_response.create( - currency="string", - name="string", - prices=[ - { - "name": "Annual fee", - "item_id": "string", - "cadence": "annual", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - } - ], + currency="currency", + name="name", + prices=[{}], ) assert response.is_closed is True @@ -300,17 +513,9 @@ 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.plans.with_streaming_response.create( - currency="string", - name="string", - prices=[ - { - "name": "Annual fee", - "item_id": "string", - "cadence": "annual", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - } - ], + currency="currency", + name="name", + prices=[{}], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -323,15 +528,16 @@ async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_update(self, async_client: AsyncOrb) -> None: plan = await async_client.plans.update( - "string", + plan_id="plan_id", ) assert_matches_type(Plan, plan, path=["response"]) @parametrize async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> None: plan = await async_client.plans.update( - "string", - external_plan_id="string", + plan_id="plan_id", + description="description", + external_plan_id="external_plan_id", metadata={"foo": "string"}, ) assert_matches_type(Plan, plan, path=["response"]) @@ -339,7 +545,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> No @parametrize async def test_raw_response_update(self, async_client: AsyncOrb) -> None: response = await async_client.plans.with_raw_response.update( - "string", + plan_id="plan_id", ) assert response.is_closed is True @@ -350,7 +556,7 @@ async def test_raw_response_update(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: async with async_client.plans.with_streaming_response.update( - "string", + plan_id="plan_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -364,7 +570,7 @@ async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: async def test_path_params_update(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): await async_client.plans.with_raw_response.update( - "", + plan_id="", ) @parametrize @@ -379,8 +585,8 @@ async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), - cursor="string", - limit=0, + cursor="cursor", + limit=1, status="active", ) assert_matches_type(AsyncPage[Plan], plan, path=["response"]) @@ -408,14 +614,14 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_fetch(self, async_client: AsyncOrb) -> None: plan = await async_client.plans.fetch( - "string", + "plan_id", ) assert_matches_type(Plan, plan, path=["response"]) @parametrize async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: response = await async_client.plans.with_raw_response.fetch( - "string", + "plan_id", ) assert response.is_closed is True @@ -426,7 +632,7 @@ async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_fetch(self, async_client: AsyncOrb) -> None: async with async_client.plans.with_streaming_response.fetch( - "string", + "plan_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/test_prices.py b/tests/api_resources/test_prices.py index f1f92e3a..f343db18 100644 --- a/tests/api_resources/test_prices.py +++ b/tests/api_resources/test_prices.py @@ -8,9 +8,15 @@ import pytest from orb import Orb, AsyncOrb -from orb.types import Price +from orb.types import ( + PriceEvaluateResponse, + PriceEvaluateMultipleResponse, + PriceEvaluatePreviewEventsResponse, +) +from orb._utils import parse_datetime from tests.utils import assert_matches_type from orb.pagination import SyncPage, AsyncPage +from orb.types.shared import Price base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -22,11 +28,11 @@ class TestPrices: def test_method_create_overload_1(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", + currency="currency", + item_id="item_id", model_type="unit", name="Annual fee", - unit_config={"unit_amount": "string"}, + unit_config={"unit_amount": "unit_amount"}, ) assert_matches_type(Price, price, path=["response"]) @@ -34,16 +40,39 @@ def test_method_create_overload_1(self, client: Orb) -> None: def test_method_create_with_all_params_overload_1(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", + currency="currency", + item_id="item_id", model_type="unit", name="Annual fee", - unit_config={"unit_amount": "string"}, - billable_metric_id="string", + unit_config={ + "unit_amount": "unit_amount", + "prorated": True, + }, + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @@ -51,11 +80,11 @@ def test_method_create_with_all_params_overload_1(self, client: Orb) -> None: def test_raw_response_create_overload_1(self, client: Orb) -> None: response = client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", + currency="currency", + item_id="item_id", model_type="unit", name="Annual fee", - unit_config={"unit_amount": "string"}, + unit_config={"unit_amount": "unit_amount"}, ) assert response.is_closed is True @@ -67,11 +96,11 @@ def test_raw_response_create_overload_1(self, client: Orb) -> None: def test_streaming_response_create_overload_1(self, client: Orb) -> None: with client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", + currency="currency", + item_id="item_id", model_type="unit", name="Annual fee", - unit_config={"unit_amount": "string"}, + unit_config={"unit_amount": "unit_amount"}, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -85,11 +114,18 @@ def test_streaming_response_create_overload_1(self, client: Orb) -> None: def test_method_create_overload_2(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="package", + currency="currency", + item_id="item_id", + model_type="tiered", name="Annual fee", - package_config={"package_amount": "string"}, + tiered_config={ + "tiers": [ + { + "first_unit": 0, + "unit_amount": "unit_amount", + } + ] + }, ) assert_matches_type(Price, price, path=["response"]) @@ -97,19 +133,45 @@ def test_method_create_overload_2(self, client: Orb) -> None: def test_method_create_with_all_params_overload_2(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="package", + currency="currency", + item_id="item_id", + model_type="tiered", name="Annual fee", - package_config={ - "package_amount": "string", - "package_size": 0, + tiered_config={ + "tiers": [ + { + "first_unit": 0, + "unit_amount": "unit_amount", + "last_unit": 0, + } + ], + "prorated": True, }, - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @@ -117,11 +179,18 @@ def test_method_create_with_all_params_overload_2(self, client: Orb) -> None: def test_raw_response_create_overload_2(self, client: Orb) -> None: response = client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="package", + currency="currency", + item_id="item_id", + model_type="tiered", name="Annual fee", - package_config={"package_amount": "string"}, + tiered_config={ + "tiers": [ + { + "first_unit": 0, + "unit_amount": "unit_amount", + } + ] + }, ) assert response.is_closed is True @@ -133,11 +202,18 @@ def test_raw_response_create_overload_2(self, client: Orb) -> None: def test_streaming_response_create_overload_2(self, client: Orb) -> None: with client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="package", + currency="currency", + item_id="item_id", + model_type="tiered", name="Annual fee", - package_config={"package_amount": "string"}, + tiered_config={ + "tiers": [ + { + "first_unit": 0, + "unit_amount": "unit_amount", + } + ] + }, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -150,28 +226,11 @@ def test_streaming_response_create_overload_2(self, client: Orb) -> None: @parametrize def test_method_create_overload_3(self, client: Orb) -> None: price = client.prices.create( + bulk_config={"tiers": [{"unit_amount": "unit_amount"}]}, cadence="annual", - currency="string", - item_id="string", - matrix_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - ], - }, - model_type="matrix", + currency="currency", + item_id="item_id", + model_type="bulk", name="Annual fee", ) assert_matches_type(Price, price, path=["response"]) @@ -179,62 +238,55 @@ def test_method_create_overload_3(self, client: Orb) -> None: @parametrize def test_method_create_with_all_params_overload_3(self, client: Orb) -> None: price = client.prices.create( - cadence="annual", - currency="string", - item_id="string", - matrix_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + bulk_config={ + "tiers": [ { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - ], + "unit_amount": "unit_amount", + "maximum_units": 0, + } + ] }, - model_type="matrix", + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk", name="Annual fee", - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize def test_raw_response_create_overload_3(self, client: Orb) -> None: response = client.prices.with_raw_response.create( + bulk_config={"tiers": [{"unit_amount": "unit_amount"}]}, cadence="annual", - currency="string", - item_id="string", - matrix_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - ], - }, - model_type="matrix", + currency="currency", + item_id="item_id", + model_type="bulk", name="Annual fee", ) @@ -246,28 +298,11 @@ def test_raw_response_create_overload_3(self, client: Orb) -> None: @parametrize def test_streaming_response_create_overload_3(self, client: Orb) -> None: with client.prices.with_streaming_response.create( + bulk_config={"tiers": [{"unit_amount": "unit_amount"}]}, cadence="annual", - currency="string", - item_id="string", - matrix_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - ], - }, - model_type="matrix", + currency="currency", + item_id="item_id", + model_type="bulk", name="Annual fee", ) as response: assert not response.is_closed @@ -281,29 +316,19 @@ def test_streaming_response_create_overload_3(self, client: Orb) -> None: @parametrize def test_method_create_overload_4(self, client: Orb) -> None: price = client.prices.create( - cadence="annual", - currency="string", - item_id="string", - matrix_with_allocation_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + bulk_with_filters_config={ + "filters": [ { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + "property_key": "x", + "property_value": "x", + } ], - "allocation": 0, + "tiers": [{"unit_amount": "unit_amount"}, {"unit_amount": "unit_amount"}], }, - model_type="matrix_with_allocation", + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_filters", name="Annual fee", ) assert_matches_type(Price, price, path=["response"]) @@ -311,64 +336,73 @@ def test_method_create_overload_4(self, client: Orb) -> None: @parametrize def test_method_create_with_all_params_overload_4(self, client: Orb) -> None: price = client.prices.create( - cadence="annual", - currency="string", - item_id="string", - matrix_with_allocation_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ + bulk_with_filters_config={ + "filters": [ { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + "property_key": "x", + "property_value": "x", + } + ], + "tiers": [ { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], + "unit_amount": "unit_amount", + "tier_lower_bound": "tier_lower_bound", }, { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], + "unit_amount": "unit_amount", + "tier_lower_bound": "tier_lower_bound", }, ], - "allocation": 0, }, - model_type="matrix_with_allocation", + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_filters", name="Annual fee", - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize def test_raw_response_create_overload_4(self, client: Orb) -> None: response = client.prices.with_raw_response.create( - cadence="annual", - currency="string", - item_id="string", - matrix_with_allocation_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + bulk_with_filters_config={ + "filters": [ { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + "property_key": "x", + "property_value": "x", + } ], - "allocation": 0, + "tiers": [{"unit_amount": "unit_amount"}, {"unit_amount": "unit_amount"}], }, - model_type="matrix_with_allocation", + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_filters", name="Annual fee", ) @@ -380,29 +414,19 @@ def test_raw_response_create_overload_4(self, client: Orb) -> None: @parametrize def test_streaming_response_create_overload_4(self, client: Orb) -> None: with client.prices.with_streaming_response.create( - cadence="annual", - currency="string", - item_id="string", - matrix_with_allocation_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + bulk_with_filters_config={ + "filters": [ { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + "property_key": "x", + "property_value": "x", + } ], - "allocation": 0, + "tiers": [{"unit_amount": "unit_amount"}, {"unit_amount": "unit_amount"}], }, - model_type="matrix_with_allocation", + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_filters", name="Annual fee", ) as response: assert not response.is_closed @@ -417,25 +441,13 @@ def test_streaming_response_create_overload_4(self, client: Orb) -> None: def test_method_create_overload_5(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered", + currency="currency", + item_id="item_id", + model_type="package", name="Annual fee", - tiered_config={ - "tiers": [ - { - "first_unit": 0, - "unit_amount": "string", - }, - { - "first_unit": 0, - "unit_amount": "string", - }, - { - "first_unit": 0, - "unit_amount": "string", - }, - ] + package_config={ + "package_amount": "package_amount", + "package_size": 1, }, ) assert_matches_type(Price, price, path=["response"]) @@ -444,34 +456,39 @@ def test_method_create_overload_5(self, client: Orb) -> None: def test_method_create_with_all_params_overload_5(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered", + currency="currency", + item_id="item_id", + model_type="package", name="Annual fee", - tiered_config={ - "tiers": [ - { - "first_unit": 0, - "last_unit": 0, - "unit_amount": "string", - }, - { - "first_unit": 0, - "last_unit": 0, - "unit_amount": "string", - }, - { - "first_unit": 0, - "last_unit": 0, - "unit_amount": "string", - }, - ] + package_config={ + "package_amount": "package_amount", + "package_size": 1, }, - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @@ -479,25 +496,13 @@ def test_method_create_with_all_params_overload_5(self, client: Orb) -> None: def test_raw_response_create_overload_5(self, client: Orb) -> None: response = client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered", + currency="currency", + item_id="item_id", + model_type="package", name="Annual fee", - tiered_config={ - "tiers": [ - { - "first_unit": 0, - "unit_amount": "string", - }, - { - "first_unit": 0, - "unit_amount": "string", - }, - { - "first_unit": 0, - "unit_amount": "string", - }, - ] + package_config={ + "package_amount": "package_amount", + "package_size": 1, }, ) @@ -510,25 +515,13 @@ def test_raw_response_create_overload_5(self, client: Orb) -> None: def test_streaming_response_create_overload_5(self, client: Orb) -> None: with client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered", + currency="currency", + item_id="item_id", + model_type="package", name="Annual fee", - tiered_config={ - "tiers": [ - { - "first_unit": 0, - "unit_amount": "string", - }, - { - "first_unit": 0, - "unit_amount": "string", - }, - { - "first_unit": 0, - "unit_amount": "string", - }, - ] + package_config={ + "package_amount": "package_amount", + "package_size": 1, }, ) as response: assert not response.is_closed @@ -543,26 +536,20 @@ def test_streaming_response_create_overload_5(self, client: Orb) -> None: def test_method_create_overload_6(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_bps", - name="Annual fee", - tiered_bps_config={ - "tiers": [ - { - "minimum_amount": "string", - "bps": 0, - }, - { - "minimum_amount": "string", - "bps": 0, - }, + currency="currency", + item_id="item_id", + matrix_config={ + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ { - "minimum_amount": "string", - "bps": 0, - }, - ] + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], }, + model_type="matrix", + name="Annual fee", ) assert_matches_type(Price, price, path=["response"]) @@ -570,37 +557,45 @@ def test_method_create_overload_6(self, client: Orb) -> None: def test_method_create_with_all_params_overload_6(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_bps", - name="Annual fee", - tiered_bps_config={ - "tiers": [ - { - "minimum_amount": "string", - "maximum_amount": "string", - "bps": 0, - "per_unit_maximum": "string", - }, - { - "minimum_amount": "string", - "maximum_amount": "string", - "bps": 0, - "per_unit_maximum": "string", - }, + currency="currency", + item_id="item_id", + matrix_config={ + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ { - "minimum_amount": "string", - "maximum_amount": "string", - "bps": 0, - "per_unit_maximum": "string", - }, - ] + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], }, - billable_metric_id="string", + model_type="matrix", + name="Annual fee", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @@ -608,26 +603,20 @@ def test_method_create_with_all_params_overload_6(self, client: Orb) -> None: def test_raw_response_create_overload_6(self, client: Orb) -> None: response = client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_bps", - name="Annual fee", - tiered_bps_config={ - "tiers": [ - { - "minimum_amount": "string", - "bps": 0, - }, - { - "minimum_amount": "string", - "bps": 0, - }, + currency="currency", + item_id="item_id", + matrix_config={ + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ { - "minimum_amount": "string", - "bps": 0, - }, - ] + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], }, + model_type="matrix", + name="Annual fee", ) assert response.is_closed is True @@ -639,26 +628,20 @@ def test_raw_response_create_overload_6(self, client: Orb) -> None: def test_streaming_response_create_overload_6(self, client: Orb) -> None: with client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_bps", - name="Annual fee", - tiered_bps_config={ - "tiers": [ + currency="currency", + item_id="item_id", + matrix_config={ + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ { - "minimum_amount": "string", - "bps": 0, - }, - { - "minimum_amount": "string", - "bps": 0, - }, - { - "minimum_amount": "string", - "bps": 0, - }, - ] + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], }, + model_type="matrix", + name="Annual fee", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -671,44 +654,95 @@ def test_streaming_response_create_overload_6(self, client: Orb) -> None: @parametrize def test_method_create_overload_7(self, client: Orb) -> None: price = client.prices.create( - bps_config={"bps": 0}, cadence="annual", - currency="string", - item_id="string", - model_type="bps", + currency="currency", + item_id="item_id", + model_type="threshold_total_amount", name="Annual fee", + threshold_total_amount_config={ + "consumption_table": [ + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + ] + }, ) assert_matches_type(Price, price, path=["response"]) @parametrize def test_method_create_with_all_params_overload_7(self, client: Orb) -> None: price = client.prices.create( - bps_config={ - "bps": 0, - "per_unit_maximum": "string", - }, cadence="annual", - currency="string", - item_id="string", - model_type="bps", + currency="currency", + item_id="item_id", + model_type="threshold_total_amount", name="Annual fee", - billable_metric_id="string", + threshold_total_amount_config={ + "consumption_table": [ + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + ], + "prorate": True, + }, + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize def test_raw_response_create_overload_7(self, client: Orb) -> None: response = client.prices.with_raw_response.create( - bps_config={"bps": 0}, cadence="annual", - currency="string", - item_id="string", - model_type="bps", + currency="currency", + item_id="item_id", + model_type="threshold_total_amount", name="Annual fee", + threshold_total_amount_config={ + "consumption_table": [ + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + ] + }, ) assert response.is_closed is True @@ -719,12 +753,23 @@ def test_raw_response_create_overload_7(self, client: Orb) -> None: @parametrize def test_streaming_response_create_overload_7(self, client: Orb) -> None: with client.prices.with_streaming_response.create( - bps_config={"bps": 0}, cadence="annual", - currency="string", - item_id="string", - model_type="bps", + currency="currency", + item_id="item_id", + model_type="threshold_total_amount", name="Annual fee", + threshold_total_amount_config={ + "consumption_table": [ + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + ] + }, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -737,59 +782,97 @@ 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}]}, cadence="annual", - currency="string", - item_id="string", - model_type="bulk_bps", + currency="currency", + item_id="item_id", + model_type="tiered_package", name="Annual fee", + tiered_package_config={ + "package_size": "package_size", + "tiers": [ + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, ) assert_matches_type(Price, price, path=["response"]) @parametrize def test_method_create_with_all_params_overload_8(self, client: Orb) -> None: price = client.prices.create( - bulk_bps_config={ + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_package", + name="Annual fee", + tiered_package_config={ + "package_size": "package_size", "tiers": [ { - "maximum_amount": "string", - "bps": 0, - "per_unit_maximum": "string", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", }, { - "maximum_amount": "string", - "bps": 0, - "per_unit_maximum": "string", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", }, - { - "maximum_amount": "string", - "bps": 0, - "per_unit_maximum": "string", - }, - ] + ], }, - cadence="annual", - currency="string", - item_id="string", - model_type="bulk_bps", - name="Annual fee", - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @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}]}, cadence="annual", - currency="string", - item_id="string", - model_type="bulk_bps", + currency="currency", + item_id="item_id", + model_type="tiered_package", name="Annual fee", + tiered_package_config={ + "package_size": "package_size", + "tiers": [ + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, ) assert response.is_closed is True @@ -800,12 +883,24 @@ 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}]}, cadence="annual", - currency="string", - item_id="string", - model_type="bulk_bps", + currency="currency", + item_id="item_id", + model_type="tiered_package", name="Annual fee", + tiered_package_config={ + "package_size": "package_size", + "tiers": [ + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -818,56 +913,102 @@ 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": "string"}, {"unit_amount": "string"}, {"unit_amount": "string"}]}, cadence="annual", - currency="string", - item_id="string", - model_type="bulk", + currency="currency", + item_id="item_id", + model_type="tiered_with_minimum", name="Annual fee", + tiered_with_minimum_config={ + "tiers": [ + { + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ] + }, ) assert_matches_type(Price, price, path=["response"]) @parametrize def test_method_create_with_all_params_overload_9(self, client: Orb) -> None: price = client.prices.create( - bulk_config={ + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_with_minimum", + name="Annual fee", + tiered_with_minimum_config={ "tiers": [ { - "maximum_units": 0, - "unit_amount": "string", - }, - { - "maximum_units": 0, - "unit_amount": "string", + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", }, { - "maximum_units": 0, - "unit_amount": "string", + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", }, - ] + ], + "hide_zero_amount_tiers": True, + "prorate": True, }, - cadence="annual", - currency="string", - item_id="string", - model_type="bulk", - name="Annual fee", - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize def test_raw_response_create_overload_9(self, client: Orb) -> None: response = client.prices.with_raw_response.create( - bulk_config={"tiers": [{"unit_amount": "string"}, {"unit_amount": "string"}, {"unit_amount": "string"}]}, cadence="annual", - currency="string", - item_id="string", - model_type="bulk", + currency="currency", + item_id="item_id", + model_type="tiered_with_minimum", name="Annual fee", + tiered_with_minimum_config={ + "tiers": [ + { + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ] + }, ) assert response.is_closed is True @@ -878,12 +1019,25 @@ 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": "string"}, {"unit_amount": "string"}, {"unit_amount": "string"}]}, cadence="annual", - currency="string", - item_id="string", - model_type="bulk", + currency="currency", + item_id="item_id", + model_type="tiered_with_minimum", name="Annual fee", + tiered_with_minimum_config={ + "tiers": [ + { + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ] + }, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -897,11 +1051,23 @@ def test_streaming_response_create_overload_9(self, client: Orb) -> None: def test_method_create_overload_10(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="threshold_total_amount", + currency="currency", + grouped_tiered_config={ + "grouping_key": "x", + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + item_id="item_id", + model_type="grouped_tiered", name="Annual fee", - threshold_total_amount_config={"foo": "bar"}, ) assert_matches_type(Price, price, path=["response"]) @@ -909,16 +1075,48 @@ def test_method_create_overload_10(self, client: Orb) -> None: def test_method_create_with_all_params_overload_10(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="threshold_total_amount", + currency="currency", + grouped_tiered_config={ + "grouping_key": "x", + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + item_id="item_id", + model_type="grouped_tiered", name="Annual fee", - threshold_total_amount_config={"foo": "bar"}, - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @@ -926,11 +1124,23 @@ def test_method_create_with_all_params_overload_10(self, client: Orb) -> None: def test_raw_response_create_overload_10(self, client: Orb) -> None: response = client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="threshold_total_amount", + currency="currency", + grouped_tiered_config={ + "grouping_key": "x", + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + item_id="item_id", + model_type="grouped_tiered", name="Annual fee", - threshold_total_amount_config={"foo": "bar"}, ) assert response.is_closed is True @@ -942,11 +1152,23 @@ def test_raw_response_create_overload_10(self, client: Orb) -> None: def test_streaming_response_create_overload_10(self, client: Orb) -> None: with client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="threshold_total_amount", + currency="currency", + grouped_tiered_config={ + "grouping_key": "x", + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + item_id="item_id", + model_type="grouped_tiered", name="Annual fee", - threshold_total_amount_config={"foo": "bar"}, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -960,11 +1182,25 @@ def test_streaming_response_create_overload_10(self, client: Orb) -> None: def test_method_create_overload_11(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package", + currency="currency", + item_id="item_id", + model_type="tiered_package_with_minimum", name="Annual fee", - tiered_package_config={"foo": "bar"}, + tiered_package_with_minimum_config={ + "package_size": 0, + "tiers": [ + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, ) assert_matches_type(Price, price, path=["response"]) @@ -972,16 +1208,50 @@ def test_method_create_overload_11(self, client: Orb) -> None: def test_method_create_with_all_params_overload_11(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package", + currency="currency", + item_id="item_id", + model_type="tiered_package_with_minimum", name="Annual fee", - tiered_package_config={"foo": "bar"}, - billable_metric_id="string", + tiered_package_with_minimum_config={ + "package_size": 0, + "tiers": [ + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @@ -989,11 +1259,25 @@ def test_method_create_with_all_params_overload_11(self, client: Orb) -> None: def test_raw_response_create_overload_11(self, client: Orb) -> None: response = client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package", + currency="currency", + item_id="item_id", + model_type="tiered_package_with_minimum", name="Annual fee", - tiered_package_config={"foo": "bar"}, + tiered_package_with_minimum_config={ + "package_size": 0, + "tiers": [ + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, ) assert response.is_closed is True @@ -1005,11 +1289,25 @@ def test_raw_response_create_overload_11(self, client: Orb) -> None: def test_streaming_response_create_overload_11(self, client: Orb) -> None: with client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package", + currency="currency", + item_id="item_id", + model_type="tiered_package_with_minimum", name="Annual fee", - tiered_package_config={"foo": "bar"}, + tiered_package_with_minimum_config={ + "package_size": 0, + "tiers": [ + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1023,11 +1321,15 @@ def test_streaming_response_create_overload_11(self, client: Orb) -> None: def test_method_create_overload_12(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_with_minimum", + currency="currency", + item_id="item_id", + model_type="package_with_allocation", name="Annual fee", - tiered_with_minimum_config={"foo": "bar"}, + package_with_allocation_config={ + "allocation": "allocation", + "package_amount": "package_amount", + "package_size": "package_size", + }, ) assert_matches_type(Price, price, path=["response"]) @@ -1035,16 +1337,40 @@ def test_method_create_overload_12(self, client: Orb) -> None: def test_method_create_with_all_params_overload_12(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_with_minimum", + currency="currency", + item_id="item_id", + model_type="package_with_allocation", name="Annual fee", - tiered_with_minimum_config={"foo": "bar"}, - billable_metric_id="string", + package_with_allocation_config={ + "allocation": "allocation", + "package_amount": "package_amount", + "package_size": "package_size", + }, + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @@ -1052,11 +1378,15 @@ def test_method_create_with_all_params_overload_12(self, client: Orb) -> None: def test_raw_response_create_overload_12(self, client: Orb) -> None: response = client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_with_minimum", + currency="currency", + item_id="item_id", + model_type="package_with_allocation", name="Annual fee", - tiered_with_minimum_config={"foo": "bar"}, + package_with_allocation_config={ + "allocation": "allocation", + "package_amount": "package_amount", + "package_size": "package_size", + }, ) assert response.is_closed is True @@ -1068,11 +1398,15 @@ def test_raw_response_create_overload_12(self, client: Orb) -> None: def test_streaming_response_create_overload_12(self, client: Orb) -> None: with client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_with_minimum", + currency="currency", + item_id="item_id", + model_type="package_with_allocation", name="Annual fee", - tiered_with_minimum_config={"foo": "bar"}, + package_with_allocation_config={ + "allocation": "allocation", + "package_amount": "package_amount", + "package_size": "package_size", + }, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1086,11 +1420,14 @@ def test_streaming_response_create_overload_12(self, client: Orb) -> None: def test_method_create_overload_13(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="package_with_allocation", + currency="currency", + item_id="item_id", + model_type="unit_with_percent", name="Annual fee", - package_with_allocation_config={"foo": "bar"}, + unit_with_percent_config={ + "percent": "percent", + "unit_amount": "unit_amount", + }, ) assert_matches_type(Price, price, path=["response"]) @@ -1098,16 +1435,39 @@ def test_method_create_overload_13(self, client: Orb) -> None: def test_method_create_with_all_params_overload_13(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="package_with_allocation", + currency="currency", + item_id="item_id", + model_type="unit_with_percent", name="Annual fee", - package_with_allocation_config={"foo": "bar"}, - billable_metric_id="string", + unit_with_percent_config={ + "percent": "percent", + "unit_amount": "unit_amount", + }, + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @@ -1115,11 +1475,14 @@ def test_method_create_with_all_params_overload_13(self, client: Orb) -> None: def test_raw_response_create_overload_13(self, client: Orb) -> None: response = client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="package_with_allocation", + currency="currency", + item_id="item_id", + model_type="unit_with_percent", name="Annual fee", - package_with_allocation_config={"foo": "bar"}, + unit_with_percent_config={ + "percent": "percent", + "unit_amount": "unit_amount", + }, ) assert response.is_closed is True @@ -1131,11 +1494,14 @@ def test_raw_response_create_overload_13(self, client: Orb) -> None: def test_streaming_response_create_overload_13(self, client: Orb) -> None: with client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="package_with_allocation", + currency="currency", + item_id="item_id", + model_type="unit_with_percent", name="Annual fee", - package_with_allocation_config={"foo": "bar"}, + unit_with_percent_config={ + "percent": "percent", + "unit_amount": "unit_amount", + }, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1149,11 +1515,21 @@ def test_streaming_response_create_overload_13(self, client: Orb) -> None: def test_method_create_overload_14(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package_with_minimum", + currency="currency", + item_id="item_id", + matrix_with_allocation_config={ + "allocation": "allocation", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix_with_allocation", name="Annual fee", - tiered_package_with_minimum_config={"foo": "bar"}, ) assert_matches_type(Price, price, path=["response"]) @@ -1161,16 +1537,46 @@ def test_method_create_overload_14(self, client: Orb) -> None: def test_method_create_with_all_params_overload_14(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package_with_minimum", + currency="currency", + item_id="item_id", + matrix_with_allocation_config={ + "allocation": "allocation", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix_with_allocation", name="Annual fee", - tiered_package_with_minimum_config={"foo": "bar"}, - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @@ -1178,12 +1584,22 @@ def test_method_create_with_all_params_overload_14(self, client: Orb) -> None: def test_raw_response_create_overload_14(self, client: Orb) -> None: response = client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package_with_minimum", - name="Annual fee", - tiered_package_with_minimum_config={"foo": "bar"}, - ) + currency="currency", + item_id="item_id", + matrix_with_allocation_config={ + "allocation": "allocation", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix_with_allocation", + name="Annual fee", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1194,11 +1610,21 @@ def test_raw_response_create_overload_14(self, client: Orb) -> None: def test_streaming_response_create_overload_14(self, client: Orb) -> None: with client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package_with_minimum", + currency="currency", + item_id="item_id", + matrix_with_allocation_config={ + "allocation": "allocation", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix_with_allocation", name="Annual fee", - tiered_package_with_minimum_config={"foo": "bar"}, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1212,11 +1638,20 @@ def test_streaming_response_create_overload_14(self, client: Orb) -> None: def test_method_create_overload_15(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="unit_with_percent", + currency="currency", + item_id="item_id", + matrix_with_threshold_discounts_config={ + "default_unit_amount": "default_unit_amount", + "first_dimension": "first_dimension", + "matrix_values": [ + { + "first_dimension_value": "first_dimension_value", + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix_with_threshold_discounts", name="Annual fee", - unit_with_percent_config={"foo": "bar"}, ) assert_matches_type(Price, price, path=["response"]) @@ -1224,16 +1659,56 @@ def test_method_create_overload_15(self, client: Orb) -> None: def test_method_create_with_all_params_overload_15(self, client: Orb) -> None: price = client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="unit_with_percent", + currency="currency", + item_id="item_id", + matrix_with_threshold_discounts_config={ + "default_unit_amount": "default_unit_amount", + "first_dimension": "first_dimension", + "matrix_values": [ + { + "first_dimension_value": "first_dimension_value", + "unit_amount": "unit_amount", + "second_dimension_value": "second_dimension_value", + } + ], + "second_dimension": "second_dimension", + "threshold_discount_groups": [ + { + "above_threshold_discount_percentage": "above_threshold_discount_percentage", + "below_threshold_discount_percentage": "below_threshold_discount_percentage", + "cell_coordinates": "cell_coordinates", + "threshold_amount": "threshold_amount", + "description": "description", + } + ], + }, + model_type="matrix_with_threshold_discounts", name="Annual fee", - unit_with_percent_config={"foo": "bar"}, - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @@ -1241,11 +1716,20 @@ def test_method_create_with_all_params_overload_15(self, client: Orb) -> None: def test_raw_response_create_overload_15(self, client: Orb) -> None: response = client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="unit_with_percent", + currency="currency", + item_id="item_id", + matrix_with_threshold_discounts_config={ + "default_unit_amount": "default_unit_amount", + "first_dimension": "first_dimension", + "matrix_values": [ + { + "first_dimension_value": "first_dimension_value", + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix_with_threshold_discounts", name="Annual fee", - unit_with_percent_config={"foo": "bar"}, ) assert response.is_closed is True @@ -1257,11 +1741,20 @@ def test_raw_response_create_overload_15(self, client: Orb) -> None: def test_streaming_response_create_overload_15(self, client: Orb) -> None: with client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="unit_with_percent", + currency="currency", + item_id="item_id", + matrix_with_threshold_discounts_config={ + "default_unit_amount": "default_unit_amount", + "first_dimension": "first_dimension", + "matrix_values": [ + { + "first_dimension_value": "first_dimension_value", + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix_with_threshold_discounts", name="Annual fee", - unit_with_percent_config={"foo": "bar"}, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1272,49 +1765,4696 @@ def test_streaming_response_create_overload_15(self, client: Orb) -> None: assert cast(Any, response.is_closed) is True @parametrize - def test_method_list(self, client: Orb) -> None: - price = client.prices.list() - assert_matches_type(SyncPage[Price], price, path=["response"]) + def test_method_create_overload_16(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_with_proration", + name="Annual fee", + tiered_with_proration_config={ + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + } + ] + }, + ) + assert_matches_type(Price, price, path=["response"]) @parametrize - def test_method_list_with_all_params(self, client: Orb) -> None: - price = client.prices.list( - cursor="string", - limit=0, + def test_method_create_with_all_params_overload_16(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_with_proration", + name="Annual fee", + tiered_with_proration_config={ + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "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, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) - assert_matches_type(SyncPage[Price], price, path=["response"]) + assert_matches_type(Price, price, path=["response"]) @parametrize - def test_raw_response_list(self, client: Orb) -> None: - response = client.prices.with_raw_response.list() + def test_raw_response_create_overload_16(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_with_proration", + name="Annual fee", + tiered_with_proration_config={ + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + } + ] + }, + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" price = response.parse() - assert_matches_type(SyncPage[Price], price, path=["response"]) + assert_matches_type(Price, price, path=["response"]) @parametrize - def test_streaming_response_list(self, client: Orb) -> None: - with client.prices.with_streaming_response.list() as response: + def test_streaming_response_create_overload_16(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_with_proration", + name="Annual fee", + tiered_with_proration_config={ + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + } + ] + }, + ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" price = response.parse() - assert_matches_type(SyncPage[Price], price, path=["response"]) + assert_matches_type(Price, price, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_method_fetch(self, client: Orb) -> None: - price = client.prices.fetch( - "string", + def test_method_create_overload_17(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit_with_proration", + name="Annual fee", + unit_with_proration_config={"unit_amount": "unit_amount"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - def test_raw_response_fetch(self, client: Orb) -> None: - response = client.prices.with_raw_response.fetch( - "string", + def test_method_create_with_all_params_overload_17(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit_with_proration", + name="Annual fee", + unit_with_proration_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, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_17(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit_with_proration", + name="Annual fee", + unit_with_proration_config={"unit_amount": "unit_amount"}, + ) + + 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_17(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit_with_proration", + name="Annual fee", + unit_with_proration_config={"unit_amount": "unit_amount"}, + ) 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_18(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + grouped_allocation_config={ + "allocation": "allocation", + "grouping_key": "x", + "overage_unit_rate": "overage_unit_rate", + }, + item_id="item_id", + model_type="grouped_allocation", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_18(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + grouped_allocation_config={ + "allocation": "allocation", + "grouping_key": "x", + "overage_unit_rate": "overage_unit_rate", + }, + item_id="item_id", + model_type="grouped_allocation", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_18(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + grouped_allocation_config={ + "allocation": "allocation", + "grouping_key": "x", + "overage_unit_rate": "overage_unit_rate", + }, + item_id="item_id", + model_type="grouped_allocation", + 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_18(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + grouped_allocation_config={ + "allocation": "allocation", + "grouping_key": "x", + "overage_unit_rate": "overage_unit_rate", + }, + item_id="item_id", + model_type="grouped_allocation", + 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_19(self, client: Orb) -> None: + price = client.prices.create( + bulk_with_proration_config={"tiers": [{"unit_amount": "unit_amount"}, {"unit_amount": "unit_amount"}]}, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_proration", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_19(self, client: Orb) -> None: + price = client.prices.create( + bulk_with_proration_config={ + "tiers": [ + { + "unit_amount": "unit_amount", + "tier_lower_bound": "tier_lower_bound", + }, + { + "unit_amount": "unit_amount", + "tier_lower_bound": "tier_lower_bound", + }, + ] + }, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_proration", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_19(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + bulk_with_proration_config={"tiers": [{"unit_amount": "unit_amount"}, {"unit_amount": "unit_amount"}]}, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_proration", + 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_19(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + bulk_with_proration_config={"tiers": [{"unit_amount": "unit_amount"}, {"unit_amount": "unit_amount"}]}, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_proration", + 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_20(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + grouped_with_prorated_minimum_config={ + "grouping_key": "x", + "minimum": "minimum", + "unit_rate": "unit_rate", + }, + item_id="item_id", + model_type="grouped_with_prorated_minimum", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_20(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + grouped_with_prorated_minimum_config={ + "grouping_key": "x", + "minimum": "minimum", + "unit_rate": "unit_rate", + }, + item_id="item_id", + model_type="grouped_with_prorated_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, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_20(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + grouped_with_prorated_minimum_config={ + "grouping_key": "x", + "minimum": "minimum", + "unit_rate": "unit_rate", + }, + item_id="item_id", + model_type="grouped_with_prorated_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_20(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + grouped_with_prorated_minimum_config={ + "grouping_key": "x", + "minimum": "minimum", + "unit_rate": "unit_rate", + }, + item_id="item_id", + model_type="grouped_with_prorated_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_21(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + grouped_with_metered_minimum_config={ + "grouping_key": "x", + "minimum_unit_amount": "minimum_unit_amount", + "pricing_key": "pricing_key", + "scaling_factors": [ + { + "scaling_factor": "scaling_factor", + "scaling_value": "scaling_value", + } + ], + "scaling_key": "scaling_key", + "unit_amounts": [ + { + "pricing_value": "pricing_value", + "unit_amount": "unit_amount", + } + ], + }, + 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={ + "grouping_key": "x", + "minimum_unit_amount": "minimum_unit_amount", + "pricing_key": "pricing_key", + "scaling_factors": [ + { + "scaling_factor": "scaling_factor", + "scaling_value": "scaling_value", + } + ], + "scaling_key": "scaling_key", + "unit_amounts": [ + { + "pricing_value": "pricing_value", + "unit_amount": "unit_amount", + } + ], + }, + 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, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + 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={ + "grouping_key": "x", + "minimum_unit_amount": "minimum_unit_amount", + "pricing_key": "pricing_key", + "scaling_factors": [ + { + "scaling_factor": "scaling_factor", + "scaling_value": "scaling_value", + } + ], + "scaling_key": "scaling_key", + "unit_amounts": [ + { + "pricing_value": "pricing_value", + "unit_amount": "unit_amount", + } + ], + }, + 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={ + "grouping_key": "x", + "minimum_unit_amount": "minimum_unit_amount", + "pricing_key": "pricing_key", + "scaling_factors": [ + { + "scaling_factor": "scaling_factor", + "scaling_value": "scaling_value", + } + ], + "scaling_key": "scaling_key", + "unit_amounts": [ + { + "pricing_value": "pricing_value", + "unit_amount": "unit_amount", + } + ], + }, + 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", + grouped_with_min_max_thresholds_config={ + "grouping_key": "x", + "maximum_charge": "maximum_charge", + "minimum_charge": "minimum_charge", + "per_unit_rate": "per_unit_rate", + }, + item_id="item_id", + model_type="grouped_with_min_max_thresholds", + 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", + grouped_with_min_max_thresholds_config={ + "grouping_key": "x", + "maximum_charge": "maximum_charge", + "minimum_charge": "minimum_charge", + "per_unit_rate": "per_unit_rate", + }, + item_id="item_id", + model_type="grouped_with_min_max_thresholds", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + 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", + grouped_with_min_max_thresholds_config={ + "grouping_key": "x", + "maximum_charge": "maximum_charge", + "minimum_charge": "minimum_charge", + "per_unit_rate": "per_unit_rate", + }, + item_id="item_id", + model_type="grouped_with_min_max_thresholds", + 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", + grouped_with_min_max_thresholds_config={ + "grouping_key": "x", + "maximum_charge": "maximum_charge", + "minimum_charge": "minimum_charge", + "per_unit_rate": "per_unit_rate", + }, + item_id="item_id", + model_type="grouped_with_min_max_thresholds", + 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( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_display_name_config={ + "dimension": "dimension", + "unit_amounts": [ + { + "dimension_value": "dimension_value", + "display_name": "display_name", + "unit_amount": "unit_amount", + } + ], + }, + 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_23(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_display_name_config={ + "dimension": "dimension", + "unit_amounts": [ + { + "dimension_value": "dimension_value", + "display_name": "display_name", + "unit_amount": "unit_amount", + } + ], + }, + 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, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_23(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_display_name_config={ + "dimension": "dimension", + "unit_amounts": [ + { + "dimension_value": "dimension_value", + "display_name": "display_name", + "unit_amount": "unit_amount", + } + ], + }, + 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_23(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_display_name_config={ + "dimension": "dimension", + "unit_amounts": [ + { + "dimension_value": "dimension_value", + "display_name": "display_name", + "unit_amount": "unit_amount", + } + ], + }, + 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_24(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + grouped_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", + "tiers": [ + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, + item_id="item_id", + model_type="grouped_tiered_package", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_24(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + grouped_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", + "tiers": [ + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, + item_id="item_id", + model_type="grouped_tiered_package", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_24(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + grouped_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", + "tiers": [ + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, + item_id="item_id", + model_type="grouped_tiered_package", + 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_24(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + grouped_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", + "tiers": [ + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, + item_id="item_id", + model_type="grouped_tiered_package", + 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_25(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + max_group_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + model_type="max_group_tiered_package", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_25(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + max_group_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + model_type="max_group_tiered_package", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_25(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + max_group_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + model_type="max_group_tiered_package", + 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_25(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + max_group_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + model_type="max_group_tiered_package", + 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_26(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_unit_pricing", + name="Annual fee", + scalable_matrix_with_unit_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ + { + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + } + ], + "unit_price": "unit_price", + }, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_26(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_unit_pricing", + name="Annual fee", + scalable_matrix_with_unit_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ + { + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + "second_dimension_value": "second_dimension_value", + } + ], + "unit_price": "unit_price", + "grouping_key": "x", + "prorate": True, + "second_dimension": "second_dimension", + }, + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_26(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_unit_pricing", + name="Annual fee", + scalable_matrix_with_unit_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ + { + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + } + ], + "unit_price": "unit_price", + }, + ) + + 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_26(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_unit_pricing", + name="Annual fee", + scalable_matrix_with_unit_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ + { + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + } + ], + "unit_price": "unit_price", + }, + ) 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_27(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_tiered_pricing", + name="Annual fee", + scalable_matrix_with_tiered_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ + { + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + } + ], + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_27(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_tiered_pricing", + name="Annual fee", + scalable_matrix_with_tiered_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ + { + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + "second_dimension_value": "second_dimension_value", + } + ], + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + "second_dimension": "second_dimension", + }, + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_27(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_tiered_pricing", + name="Annual fee", + scalable_matrix_with_tiered_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ + { + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + } + ], + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + ) + + 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_27(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_tiered_pricing", + name="Annual fee", + scalable_matrix_with_tiered_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ + { + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + } + ], + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + ) 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_28(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + cumulative_grouped_bulk_config={ + "dimension_values": [ + { + "grouping_key": "x", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + } + ], + "group": "group", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_28(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + cumulative_grouped_bulk_config={ + "dimension_values": [ + { + "grouping_key": "x", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + } + ], + "group": "group", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_28(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + cumulative_grouped_bulk_config={ + "dimension_values": [ + { + "grouping_key": "x", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + } + ], + "group": "group", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", + 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_28(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + cumulative_grouped_bulk_config={ + "dimension_values": [ + { + "grouping_key": "x", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + } + ], + "group": "group", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", + 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_29(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + cumulative_grouped_allocation_config={ + "cumulative_allocation": "cumulative_allocation", + "group_allocation": "group_allocation", + "grouping_key": "x", + "unit_amount": "unit_amount", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_allocation", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_29(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + cumulative_grouped_allocation_config={ + "cumulative_allocation": "cumulative_allocation", + "group_allocation": "group_allocation", + "grouping_key": "x", + "unit_amount": "unit_amount", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_allocation", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_29(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + cumulative_grouped_allocation_config={ + "cumulative_allocation": "cumulative_allocation", + "group_allocation": "group_allocation", + "grouping_key": "x", + "unit_amount": "unit_amount", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_allocation", + 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_29(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + cumulative_grouped_allocation_config={ + "cumulative_allocation": "cumulative_allocation", + "group_allocation": "group_allocation", + "grouping_key": "x", + "unit_amount": "unit_amount", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_allocation", + 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_30(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + daily_credit_allowance_config={ + "daily_allowance": "daily_allowance", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "event_day_property": "x", + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + item_id="item_id", + model_type="daily_credit_allowance", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_30(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + daily_credit_allowance_config={ + "daily_allowance": "daily_allowance", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "event_day_property": "x", + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + item_id="item_id", + model_type="daily_credit_allowance", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_30(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + daily_credit_allowance_config={ + "daily_allowance": "daily_allowance", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "event_day_property": "x", + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + item_id="item_id", + model_type="daily_credit_allowance", + 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_30(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + daily_credit_allowance_config={ + "daily_allowance": "daily_allowance", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "event_day_property": "x", + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + item_id="item_id", + model_type="daily_credit_allowance", + 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_31(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + metered_allowance_config={ + "allowance_grouping_value": "x", + "consumption_grouping_value": "x", + "grouping_key": "x", + "unit_amount": "unit_amount", + }, + model_type="metered_allowance", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_31(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + metered_allowance_config={ + "allowance_grouping_value": "x", + "consumption_grouping_value": "x", + "grouping_key": "x", + "unit_amount": "unit_amount", + "allowance_display_name": "x", + "consumption_display_name": "x", + }, + model_type="metered_allowance", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_31(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + metered_allowance_config={ + "allowance_grouping_value": "x", + "consumption_grouping_value": "x", + "grouping_key": "x", + "unit_amount": "unit_amount", + }, + model_type="metered_allowance", + 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_31(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + metered_allowance_config={ + "allowance_grouping_value": "x", + "consumption_grouping_value": "x", + "grouping_key": "x", + "unit_amount": "unit_amount", + }, + model_type="metered_allowance", + 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_32(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + minimum_composite_config={"minimum_amount": "minimum_amount"}, + model_type="minimum_composite", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_32(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + minimum_composite_config={ + "minimum_amount": "minimum_amount", + "prorated": True, + }, + model_type="minimum_composite", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_32(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + minimum_composite_config={"minimum_amount": "minimum_amount"}, + model_type="minimum_composite", + 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_32(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + minimum_composite_config={"minimum_amount": "minimum_amount"}, + model_type="minimum_composite", + 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_33(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="percent", + name="Annual fee", + percent_config={"percent": 1}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_33(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="percent", + name="Annual fee", + percent_config={ + "percent": 1, + "maximum_amount": "maximum_amount", + "minimum_amount": "minimum_amount", + "prorated": True, + }, + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_33(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="percent", + name="Annual fee", + percent_config={"percent": 1}, + ) + + 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_33(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="percent", + name="Annual fee", + percent_config={"percent": 1}, + ) 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_34(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + event_output_config={"unit_rating_key": "x"}, + item_id="item_id", + model_type="event_output", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_34(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + event_output_config={ + "unit_rating_key": "x", + "default_unit_rate": "default_unit_rate", + "grouping_key": "grouping_key", + }, + item_id="item_id", + model_type="event_output", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_34(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + event_output_config={"unit_rating_key": "x"}, + item_id="item_id", + model_type="event_output", + 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_34(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + event_output_config={"unit_rating_key": "x"}, + item_id="item_id", + model_type="event_output", + 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_update(self, client: Orb) -> None: + price = client.prices.update( + price_id="price_id", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Orb) -> None: + price = client.prices.update( + price_id="price_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Orb) -> None: + response = client.prices.with_raw_response.update( + price_id="price_id", + ) + + 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_update(self, client: Orb) -> None: + with client.prices.with_streaming_response.update( + price_id="price_id", + ) 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_path_params_update(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `price_id` but received ''"): + client.prices.with_raw_response.update( + price_id="", + ) + + @parametrize + def test_method_list(self, client: Orb) -> None: + price = client.prices.list() + assert_matches_type(SyncPage[Price], price, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Orb) -> None: + price = client.prices.list( + cursor="cursor", + limit=1, + ) + assert_matches_type(SyncPage[Price], price, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Orb) -> None: + response = client.prices.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + price = response.parse() + assert_matches_type(SyncPage[Price], price, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Orb) -> None: + with client.prices.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + price = response.parse() + assert_matches_type(SyncPage[Price], price, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_evaluate(self, client: Orb) -> None: + price = client.prices.evaluate( + price_id="price_id", + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(PriceEvaluateResponse, price, path=["response"]) + + @parametrize + def test_method_evaluate_with_all_params(self, client: Orb) -> None: + price = client.prices.evaluate( + price_id="price_id", + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + customer_id="customer_id", + external_customer_id="external_customer_id", + filter="my_numeric_property > 100 AND my_other_property = 'bar'", + grouping_keys=["case when my_event_type = 'foo' then true else false end"], + metric_parameter_overrides={"foo": "bar"}, + ) + assert_matches_type(PriceEvaluateResponse, price, path=["response"]) + + @parametrize + def test_raw_response_evaluate(self, client: Orb) -> None: + response = client.prices.with_raw_response.evaluate( + price_id="price_id", + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" + price = response.parse() + assert_matches_type(PriceEvaluateResponse, price, path=["response"]) + + @parametrize + def test_streaming_response_evaluate(self, client: Orb) -> None: + with client.prices.with_streaming_response.evaluate( + price_id="price_id", + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" + + price = response.parse() + assert_matches_type(PriceEvaluateResponse, price, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_evaluate(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `price_id` but received ''"): + client.prices.with_raw_response.evaluate( + price_id="", + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + + @parametrize + def test_method_evaluate_multiple(self, client: Orb) -> None: + price = client.prices.evaluate_multiple( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(PriceEvaluateMultipleResponse, price, path=["response"]) + + @parametrize + def test_method_evaluate_multiple_with_all_params(self, client: Orb) -> None: + price = client.prices.evaluate_multiple( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + customer_id="customer_id", + external_customer_id="external_customer_id", + price_evaluations=[ + { + "external_price_id": "external_price_id", + "filter": "my_numeric_property > 100 AND my_other_property = 'bar'", + "grouping_keys": ["case when my_event_type = 'foo' then true else false end"], + "metric_parameter_overrides": {"foo": "bar"}, + "price": { + "cadence": "annual", + "currency": "currency", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + }, + "price_id": "price_id", + } + ], + ) + assert_matches_type(PriceEvaluateMultipleResponse, price, path=["response"]) + + @parametrize + def test_raw_response_evaluate_multiple(self, client: Orb) -> None: + response = client.prices.with_raw_response.evaluate_multiple( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" + price = response.parse() + assert_matches_type(PriceEvaluateMultipleResponse, price, path=["response"]) + + @parametrize + def test_streaming_response_evaluate_multiple(self, client: Orb) -> None: + with client.prices.with_streaming_response.evaluate_multiple( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" + + price = response.parse() + assert_matches_type(PriceEvaluateMultipleResponse, price, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_evaluate_preview_events(self, client: Orb) -> None: + price = client.prices.evaluate_preview_events( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(PriceEvaluatePreviewEventsResponse, price, path=["response"]) + + @parametrize + def test_method_evaluate_preview_events_with_all_params(self, client: Orb) -> None: + price = client.prices.evaluate_preview_events( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + customer_id="customer_id", + events=[ + { + "event_name": "event_name", + "properties": {"foo": "bar"}, + "timestamp": parse_datetime("2020-12-09T16:09:53Z"), + "customer_id": "customer_id", + "external_customer_id": "external_customer_id", + } + ], + external_customer_id="external_customer_id", + price_evaluations=[ + { + "external_price_id": "external_price_id", + "filter": "my_numeric_property > 100 AND my_other_property = 'bar'", + "grouping_keys": ["case when my_event_type = 'foo' then true else false end"], + "metric_parameter_overrides": {"foo": "bar"}, + "price": { + "cadence": "annual", + "currency": "currency", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + }, + "price_id": "price_id", + } + ], + ) + assert_matches_type(PriceEvaluatePreviewEventsResponse, price, path=["response"]) + + @parametrize + def test_raw_response_evaluate_preview_events(self, client: Orb) -> None: + response = client.prices.with_raw_response.evaluate_preview_events( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" + price = response.parse() + assert_matches_type(PriceEvaluatePreviewEventsResponse, price, path=["response"]) + + @parametrize + def test_streaming_response_evaluate_preview_events(self, client: Orb) -> None: + with client.prices.with_streaming_response.evaluate_preview_events( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" + + price = response.parse() + assert_matches_type(PriceEvaluatePreviewEventsResponse, price, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_fetch(self, client: Orb) -> None: + price = client.prices.fetch( + "price_id", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_fetch(self, client: Orb) -> None: + response = client.prices.with_raw_response.fetch( + "price_id", + ) + + 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_fetch(self, client: Orb) -> None: + with client.prices.with_streaming_response.fetch( + "price_id", + ) 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_path_params_fetch(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `price_id` but received ''"): + client.prices.with_raw_response.fetch( + "", + ) + + +class TestAsyncPrices: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create_overload_1(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit", + name="Annual fee", + unit_config={"unit_amount": "unit_amount"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_1(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit", + name="Annual fee", + unit_config={ + "unit_amount": "unit_amount", + "prorated": True, + }, + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_1(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit", + name="Annual fee", + unit_config={"unit_amount": "unit_amount"}, + ) + + 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_1(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit", + name="Annual fee", + unit_config={"unit_amount": "unit_amount"}, + ) 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_2(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered", + name="Annual fee", + tiered_config={ + "tiers": [ + { + "first_unit": 0, + "unit_amount": "unit_amount", + } + ] + }, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_2(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered", + name="Annual fee", + tiered_config={ + "tiers": [ + { + "first_unit": 0, + "unit_amount": "unit_amount", + "last_unit": 0, + } + ], + "prorated": True, + }, + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_2(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered", + name="Annual fee", + tiered_config={ + "tiers": [ + { + "first_unit": 0, + "unit_amount": "unit_amount", + } + ] + }, + ) + + 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_2(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered", + name="Annual fee", + tiered_config={ + "tiers": [ + { + "first_unit": 0, + "unit_amount": "unit_amount", + } + ] + }, + ) 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_3(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + bulk_config={"tiers": [{"unit_amount": "unit_amount"}]}, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_3(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + bulk_config={ + "tiers": [ + { + "unit_amount": "unit_amount", + "maximum_units": 0, + } + ] + }, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_3(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + bulk_config={"tiers": [{"unit_amount": "unit_amount"}]}, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk", + 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_3(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + bulk_config={"tiers": [{"unit_amount": "unit_amount"}]}, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk", + 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_4(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + bulk_with_filters_config={ + "filters": [ + { + "property_key": "x", + "property_value": "x", + } + ], + "tiers": [{"unit_amount": "unit_amount"}, {"unit_amount": "unit_amount"}], + }, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_filters", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_4(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + bulk_with_filters_config={ + "filters": [ + { + "property_key": "x", + "property_value": "x", + } + ], + "tiers": [ + { + "unit_amount": "unit_amount", + "tier_lower_bound": "tier_lower_bound", + }, + { + "unit_amount": "unit_amount", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_filters", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_4(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + bulk_with_filters_config={ + "filters": [ + { + "property_key": "x", + "property_value": "x", + } + ], + "tiers": [{"unit_amount": "unit_amount"}, {"unit_amount": "unit_amount"}], + }, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_filters", + 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_4(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + bulk_with_filters_config={ + "filters": [ + { + "property_key": "x", + "property_value": "x", + } + ], + "tiers": [{"unit_amount": "unit_amount"}, {"unit_amount": "unit_amount"}], + }, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_filters", + 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_5(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="package", + name="Annual fee", + package_config={ + "package_amount": "package_amount", + "package_size": 1, + }, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_5(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="package", + name="Annual fee", + package_config={ + "package_amount": "package_amount", + "package_size": 1, + }, + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_5(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="package", + name="Annual fee", + package_config={ + "package_amount": "package_amount", + "package_size": 1, + }, + ) + + 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_5(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="package", + name="Annual fee", + package_config={ + "package_amount": "package_amount", + "package_size": 1, + }, + ) 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_6(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_config={ + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_6(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_config={ + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_6(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_config={ + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix", + 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_6(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_config={ + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix", + 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_7(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="threshold_total_amount", + name="Annual fee", + threshold_total_amount_config={ + "consumption_table": [ + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + ] + }, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_7(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="threshold_total_amount", + name="Annual fee", + threshold_total_amount_config={ + "consumption_table": [ + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + ], + "prorate": True, + }, + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_7(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="threshold_total_amount", + name="Annual fee", + threshold_total_amount_config={ + "consumption_table": [ + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + ] + }, + ) + + 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_7(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="threshold_total_amount", + name="Annual fee", + threshold_total_amount_config={ + "consumption_table": [ + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + { + "threshold": "threshold", + "total_amount": "total_amount", + }, + ] + }, + ) 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_8(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_package", + name="Annual fee", + tiered_package_config={ + "package_size": "package_size", + "tiers": [ + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_8(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_package", + name="Annual fee", + tiered_package_config={ + "package_size": "package_size", + "tiers": [ + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_8(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_package", + name="Annual fee", + tiered_package_config={ + "package_size": "package_size", + "tiers": [ + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, + ) + + 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_8(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_package", + name="Annual fee", + tiered_package_config={ + "package_size": "package_size", + "tiers": [ + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, + ) 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_9(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_with_minimum", + name="Annual fee", + tiered_with_minimum_config={ + "tiers": [ + { + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ] + }, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_9(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_with_minimum", + name="Annual fee", + tiered_with_minimum_config={ + "tiers": [ + { + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + "hide_zero_amount_tiers": True, + "prorate": True, + }, + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_9(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_with_minimum", + name="Annual fee", + tiered_with_minimum_config={ + "tiers": [ + { + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ] + }, + ) + + 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_9(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_with_minimum", + name="Annual fee", + tiered_with_minimum_config={ + "tiers": [ + { + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "minimum_amount": "minimum_amount", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ] + }, + ) 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_10(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + grouped_tiered_config={ + "grouping_key": "x", + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + item_id="item_id", + model_type="grouped_tiered", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_10(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + grouped_tiered_config={ + "grouping_key": "x", + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + item_id="item_id", + model_type="grouped_tiered", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_10(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + grouped_tiered_config={ + "grouping_key": "x", + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + item_id="item_id", + model_type="grouped_tiered", + 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_10(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + grouped_tiered_config={ + "grouping_key": "x", + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, + item_id="item_id", + model_type="grouped_tiered", + 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_11(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_package_with_minimum", + name="Annual fee", + tiered_package_with_minimum_config={ + "package_size": 0, + "tiers": [ + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_11(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_package_with_minimum", + name="Annual fee", + tiered_package_with_minimum_config={ + "package_size": 0, + "tiers": [ + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_11(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_package_with_minimum", + name="Annual fee", + tiered_package_with_minimum_config={ + "package_size": 0, + "tiers": [ + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, + ) + + 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_11(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_package_with_minimum", + name="Annual fee", + tiered_package_with_minimum_config={ + "package_size": 0, + "tiers": [ + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + { + "minimum_amount": "minimum_amount", + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", + }, + ], + }, + ) 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_12(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="package_with_allocation", + name="Annual fee", + package_with_allocation_config={ + "allocation": "allocation", + "package_amount": "package_amount", + "package_size": "package_size", + }, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_12(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="package_with_allocation", + name="Annual fee", + package_with_allocation_config={ + "allocation": "allocation", + "package_amount": "package_amount", + "package_size": "package_size", + }, + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_12(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="package_with_allocation", + name="Annual fee", + package_with_allocation_config={ + "allocation": "allocation", + "package_amount": "package_amount", + "package_size": "package_size", + }, + ) + + 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_12(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="package_with_allocation", + name="Annual fee", + package_with_allocation_config={ + "allocation": "allocation", + "package_amount": "package_amount", + "package_size": "package_size", + }, + ) 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_13(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit_with_percent", + name="Annual fee", + unit_with_percent_config={ + "percent": "percent", + "unit_amount": "unit_amount", + }, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_13(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit_with_percent", + name="Annual fee", + unit_with_percent_config={ + "percent": "percent", + "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, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_13(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit_with_percent", + name="Annual fee", + unit_with_percent_config={ + "percent": "percent", + "unit_amount": "unit_amount", + }, + ) + + 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_13(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit_with_percent", + name="Annual fee", + unit_with_percent_config={ + "percent": "percent", + "unit_amount": "unit_amount", + }, + ) 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_14(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_allocation_config={ + "allocation": "allocation", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix_with_allocation", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_14(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_allocation_config={ + "allocation": "allocation", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix_with_allocation", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_14(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_allocation_config={ + "allocation": "allocation", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix_with_allocation", + 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_14(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_allocation_config={ + "allocation": "allocation", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix_with_allocation", + 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_15(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_threshold_discounts_config={ + "default_unit_amount": "default_unit_amount", + "first_dimension": "first_dimension", + "matrix_values": [ + { + "first_dimension_value": "first_dimension_value", + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix_with_threshold_discounts", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_15(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_threshold_discounts_config={ + "default_unit_amount": "default_unit_amount", + "first_dimension": "first_dimension", + "matrix_values": [ + { + "first_dimension_value": "first_dimension_value", + "unit_amount": "unit_amount", + "second_dimension_value": "second_dimension_value", + } + ], + "second_dimension": "second_dimension", + "threshold_discount_groups": [ + { + "above_threshold_discount_percentage": "above_threshold_discount_percentage", + "below_threshold_discount_percentage": "below_threshold_discount_percentage", + "cell_coordinates": "cell_coordinates", + "threshold_amount": "threshold_amount", + "description": "description", + } + ], + }, + model_type="matrix_with_threshold_discounts", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_15(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_threshold_discounts_config={ + "default_unit_amount": "default_unit_amount", + "first_dimension": "first_dimension", + "matrix_values": [ + { + "first_dimension_value": "first_dimension_value", + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix_with_threshold_discounts", + 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_15(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_threshold_discounts_config={ + "default_unit_amount": "default_unit_amount", + "first_dimension": "first_dimension", + "matrix_values": [ + { + "first_dimension_value": "first_dimension_value", + "unit_amount": "unit_amount", + } + ], + }, + model_type="matrix_with_threshold_discounts", + 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_16(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_with_proration", + name="Annual fee", + tiered_with_proration_config={ + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + } + ] + }, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_16(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_with_proration", + name="Annual fee", + tiered_with_proration_config={ + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "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, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_16(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_with_proration", + name="Annual fee", + tiered_with_proration_config={ + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + } + ] + }, + ) + + 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_16(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="tiered_with_proration", + name="Annual fee", + tiered_with_proration_config={ + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + } + ] + }, + ) 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_17(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit_with_proration", + name="Annual fee", + unit_with_proration_config={"unit_amount": "unit_amount"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_17(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit_with_proration", + name="Annual fee", + unit_with_proration_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, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_17(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit_with_proration", + name="Annual fee", + unit_with_proration_config={"unit_amount": "unit_amount"}, + ) + + 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_17(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + model_type="unit_with_proration", + name="Annual fee", + unit_with_proration_config={"unit_amount": "unit_amount"}, + ) 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_18(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + grouped_allocation_config={ + "allocation": "allocation", + "grouping_key": "x", + "overage_unit_rate": "overage_unit_rate", + }, + item_id="item_id", + model_type="grouped_allocation", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_18(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + grouped_allocation_config={ + "allocation": "allocation", + "grouping_key": "x", + "overage_unit_rate": "overage_unit_rate", + }, + item_id="item_id", + model_type="grouped_allocation", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_18(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + grouped_allocation_config={ + "allocation": "allocation", + "grouping_key": "x", + "overage_unit_rate": "overage_unit_rate", + }, + item_id="item_id", + model_type="grouped_allocation", + 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_18(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + grouped_allocation_config={ + "allocation": "allocation", + "grouping_key": "x", + "overage_unit_rate": "overage_unit_rate", + }, + item_id="item_id", + model_type="grouped_allocation", + 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_19(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + bulk_with_proration_config={"tiers": [{"unit_amount": "unit_amount"}, {"unit_amount": "unit_amount"}]}, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_proration", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_19(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + bulk_with_proration_config={ + "tiers": [ + { + "unit_amount": "unit_amount", + "tier_lower_bound": "tier_lower_bound", + }, + { + "unit_amount": "unit_amount", + "tier_lower_bound": "tier_lower_bound", + }, + ] + }, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_proration", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_19(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + bulk_with_proration_config={"tiers": [{"unit_amount": "unit_amount"}, {"unit_amount": "unit_amount"}]}, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_proration", + 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_19(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + bulk_with_proration_config={"tiers": [{"unit_amount": "unit_amount"}, {"unit_amount": "unit_amount"}]}, + cadence="annual", + currency="currency", + item_id="item_id", + model_type="bulk_with_proration", + 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_20(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + grouped_with_prorated_minimum_config={ + "grouping_key": "x", + "minimum": "minimum", + "unit_rate": "unit_rate", + }, + item_id="item_id", + model_type="grouped_with_prorated_minimum", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_20(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + grouped_with_prorated_minimum_config={ + "grouping_key": "x", + "minimum": "minimum", + "unit_rate": "unit_rate", + }, + item_id="item_id", + model_type="grouped_with_prorated_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, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_20(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + grouped_with_prorated_minimum_config={ + "grouping_key": "x", + "minimum": "minimum", + "unit_rate": "unit_rate", + }, + item_id="item_id", + model_type="grouped_with_prorated_minimum", + name="Annual fee", ) assert response.is_closed is True @@ -1323,67 +6463,136 @@ def test_raw_response_fetch(self, client: Orb) -> None: assert_matches_type(Price, price, path=["response"]) @parametrize - def test_streaming_response_fetch(self, client: Orb) -> None: - with client.prices.with_streaming_response.fetch( - "string", + async def test_streaming_response_create_overload_20(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + grouped_with_prorated_minimum_config={ + "grouping_key": "x", + "minimum": "minimum", + "unit_rate": "unit_rate", + }, + item_id="item_id", + model_type="grouped_with_prorated_minimum", + name="Annual fee", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" - price = response.parse() + price = await response.parse() assert_matches_type(Price, price, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_fetch(self, client: Orb) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `price_id` but received ''"): - client.prices.with_raw_response.fetch( - "", - ) - - -class TestAsyncPrices: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - async def test_method_create_overload_1(self, async_client: AsyncOrb) -> None: + async def test_method_create_overload_21(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="unit", + currency="currency", + grouped_with_metered_minimum_config={ + "grouping_key": "x", + "minimum_unit_amount": "minimum_unit_amount", + "pricing_key": "pricing_key", + "scaling_factors": [ + { + "scaling_factor": "scaling_factor", + "scaling_value": "scaling_value", + } + ], + "scaling_key": "scaling_key", + "unit_amounts": [ + { + "pricing_value": "pricing_value", + "unit_amount": "unit_amount", + } + ], + }, + item_id="item_id", + model_type="grouped_with_metered_minimum", name="Annual fee", - unit_config={"unit_amount": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_1(self, async_client: AsyncOrb) -> None: + async def test_method_create_with_all_params_overload_21(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="unit", + currency="currency", + grouped_with_metered_minimum_config={ + "grouping_key": "x", + "minimum_unit_amount": "minimum_unit_amount", + "pricing_key": "pricing_key", + "scaling_factors": [ + { + "scaling_factor": "scaling_factor", + "scaling_value": "scaling_value", + } + ], + "scaling_key": "scaling_key", + "unit_amounts": [ + { + "pricing_value": "pricing_value", + "unit_amount": "unit_amount", + } + ], + }, + item_id="item_id", + model_type="grouped_with_metered_minimum", name="Annual fee", - unit_config={"unit_amount": "string"}, - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_1(self, async_client: AsyncOrb) -> None: + 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="string", - item_id="string", - model_type="unit", + currency="currency", + grouped_with_metered_minimum_config={ + "grouping_key": "x", + "minimum_unit_amount": "minimum_unit_amount", + "pricing_key": "pricing_key", + "scaling_factors": [ + { + "scaling_factor": "scaling_factor", + "scaling_value": "scaling_value", + } + ], + "scaling_key": "scaling_key", + "unit_amounts": [ + { + "pricing_value": "pricing_value", + "unit_amount": "unit_amount", + } + ], + }, + item_id="item_id", + model_type="grouped_with_metered_minimum", name="Annual fee", - unit_config={"unit_amount": "string"}, ) assert response.is_closed is True @@ -1392,14 +6601,31 @@ async def test_raw_response_create_overload_1(self, async_client: AsyncOrb) -> N assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_1(self, async_client: AsyncOrb) -> None: + 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="string", - item_id="string", - model_type="unit", + currency="currency", + grouped_with_metered_minimum_config={ + "grouping_key": "x", + "minimum_unit_amount": "minimum_unit_amount", + "pricing_key": "pricing_key", + "scaling_factors": [ + { + "scaling_factor": "scaling_factor", + "scaling_value": "scaling_value", + } + ], + "scaling_key": "scaling_key", + "unit_amounts": [ + { + "pricing_value": "pricing_value", + "unit_amount": "unit_amount", + } + ], + }, + item_id="item_id", + model_type="grouped_with_metered_minimum", name="Annual fee", - unit_config={"unit_amount": "string"}, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1410,46 +6636,78 @@ async def test_streaming_response_create_overload_1(self, async_client: AsyncOrb assert cast(Any, response.is_closed) is True @parametrize - async def test_method_create_overload_2(self, async_client: AsyncOrb) -> None: + async def test_method_create_overload_22(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="package", + currency="currency", + grouped_with_min_max_thresholds_config={ + "grouping_key": "x", + "maximum_charge": "maximum_charge", + "minimum_charge": "minimum_charge", + "per_unit_rate": "per_unit_rate", + }, + item_id="item_id", + model_type="grouped_with_min_max_thresholds", name="Annual fee", - package_config={"package_amount": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_2(self, async_client: AsyncOrb) -> None: + async def test_method_create_with_all_params_overload_22(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="package", - name="Annual fee", - package_config={ - "package_amount": "string", - "package_size": 0, + currency="currency", + grouped_with_min_max_thresholds_config={ + "grouping_key": "x", + "maximum_charge": "maximum_charge", + "minimum_charge": "minimum_charge", + "per_unit_rate": "per_unit_rate", }, - billable_metric_id="string", + item_id="item_id", + model_type="grouped_with_min_max_thresholds", + name="Annual fee", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_2(self, async_client: AsyncOrb) -> None: + 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="string", - item_id="string", - model_type="package", + currency="currency", + grouped_with_min_max_thresholds_config={ + "grouping_key": "x", + "maximum_charge": "maximum_charge", + "minimum_charge": "minimum_charge", + "per_unit_rate": "per_unit_rate", + }, + item_id="item_id", + model_type="grouped_with_min_max_thresholds", name="Annual fee", - package_config={"package_amount": "string"}, ) assert response.is_closed is True @@ -1458,14 +6716,19 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOrb) -> N assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_2(self, async_client: AsyncOrb) -> None: + 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="string", - item_id="string", - model_type="package", + currency="currency", + grouped_with_min_max_thresholds_config={ + "grouping_key": "x", + "maximum_charge": "maximum_charge", + "minimum_charge": "minimum_charge", + "per_unit_rate": "per_unit_rate", + }, + item_id="item_id", + model_type="grouped_with_min_max_thresholds", name="Annual fee", - package_config={"package_amount": "string"}, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1476,93 +6739,89 @@ async def test_streaming_response_create_overload_2(self, async_client: AsyncOrb assert cast(Any, response.is_closed) is True @parametrize - async def test_method_create_overload_3(self, async_client: AsyncOrb) -> None: + async def test_method_create_overload_23(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - matrix_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ + currency="currency", + item_id="item_id", + matrix_with_display_name_config={ + "dimension": "dimension", + "unit_amounts": [ { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + "dimension_value": "dimension_value", + "display_name": "display_name", + "unit_amount": "unit_amount", + } ], }, - model_type="matrix", + 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_3(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( cadence="annual", - currency="string", - item_id="string", - matrix_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + currency="currency", + item_id="item_id", + matrix_with_display_name_config={ + "dimension": "dimension", + "unit_amounts": [ { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + "dimension_value": "dimension_value", + "display_name": "display_name", + "unit_amount": "unit_amount", + } ], }, - model_type="matrix", + model_type="matrix_with_display_name", name="Annual fee", - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_3(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( cadence="annual", - currency="string", - item_id="string", - matrix_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + currency="currency", + item_id="item_id", + matrix_with_display_name_config={ + "dimension": "dimension", + "unit_amounts": [ { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + "dimension_value": "dimension_value", + "display_name": "display_name", + "unit_amount": "unit_amount", + } ], }, - model_type="matrix", + model_type="matrix_with_display_name", name="Annual fee", ) @@ -1572,30 +6831,22 @@ async def test_raw_response_create_overload_3(self, async_client: AsyncOrb) -> N assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_3(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( cadence="annual", - currency="string", - item_id="string", - matrix_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + currency="currency", + item_id="item_id", + matrix_with_display_name_config={ + "dimension": "dimension", + "unit_amounts": [ { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + "dimension_value": "dimension_value", + "display_name": "display_name", + "unit_amount": "unit_amount", + } ], }, - model_type="matrix", + model_type="matrix_with_display_name", name="Annual fee", ) as response: assert not response.is_closed @@ -1607,96 +6858,101 @@ async def test_streaming_response_create_overload_3(self, async_client: AsyncOrb assert cast(Any, response.is_closed) is True @parametrize - async def test_method_create_overload_4(self, async_client: AsyncOrb) -> None: + async def test_method_create_overload_24(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - matrix_with_allocation_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + currency="currency", + grouped_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", + "tiers": [ { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", }, { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", }, ], - "allocation": 0, }, - model_type="matrix_with_allocation", + item_id="item_id", + model_type="grouped_tiered_package", name="Annual fee", ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_4(self, async_client: AsyncOrb) -> None: + async def test_method_create_with_all_params_overload_24(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - matrix_with_allocation_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + currency="currency", + grouped_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", + "tiers": [ { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", }, { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", }, ], - "allocation": 0, }, - model_type="matrix_with_allocation", + item_id="item_id", + model_type="grouped_tiered_package", name="Annual fee", - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_4(self, async_client: AsyncOrb) -> None: + async def test_raw_response_create_overload_24(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - matrix_with_allocation_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + currency="currency", + grouped_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", + "tiers": [ { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", }, { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", }, ], - "allocation": 0, }, - model_type="matrix_with_allocation", + item_id="item_id", + model_type="grouped_tiered_package", name="Annual fee", ) @@ -1706,31 +6962,26 @@ async def test_raw_response_create_overload_4(self, async_client: AsyncOrb) -> N assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_4(self, async_client: AsyncOrb) -> None: + async def test_streaming_response_create_overload_24(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - matrix_with_allocation_config={ - "dimensions": ["string", "string", "string"], - "default_unit_amount": "string", - "matrix_values": [ - { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], - }, + currency="currency", + grouped_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", + "tiers": [ { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", }, { - "unit_amount": "string", - "dimension_values": ["string", "string", "string"], + "per_unit": "per_unit", + "tier_lower_bound": "tier_lower_bound", }, ], - "allocation": 0, }, - model_type="matrix_with_allocation", + item_id="item_id", + model_type="grouped_tiered_package", name="Annual fee", ) as response: assert not response.is_closed @@ -1742,91 +6993,102 @@ async def test_streaming_response_create_overload_4(self, async_client: AsyncOrb assert cast(Any, response.is_closed) is True @parametrize - async def test_method_create_overload_5(self, async_client: AsyncOrb) -> None: + async def test_method_create_overload_25(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered", - name="Annual fee", - tiered_config={ + currency="currency", + item_id="item_id", + max_group_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", "tiers": [ { - "first_unit": 0, - "unit_amount": "string", - }, - { - "first_unit": 0, - "unit_amount": "string", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", }, { - "first_unit": 0, - "unit_amount": "string", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", }, - ] + ], }, + model_type="max_group_tiered_package", + name="Annual fee", ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_5(self, async_client: AsyncOrb) -> None: + async def test_method_create_with_all_params_overload_25(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered", - name="Annual fee", - tiered_config={ + currency="currency", + item_id="item_id", + max_group_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", "tiers": [ { - "first_unit": 0, - "last_unit": 0, - "unit_amount": "string", - }, - { - "first_unit": 0, - "last_unit": 0, - "unit_amount": "string", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", }, { - "first_unit": 0, - "last_unit": 0, - "unit_amount": "string", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", }, - ] + ], }, - billable_metric_id="string", + model_type="max_group_tiered_package", + name="Annual fee", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_5(self, async_client: AsyncOrb) -> None: + async def test_raw_response_create_overload_25(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered", - name="Annual fee", - tiered_config={ + currency="currency", + item_id="item_id", + max_group_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", "tiers": [ { - "first_unit": 0, - "unit_amount": "string", - }, - { - "first_unit": 0, - "unit_amount": "string", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", }, { - "first_unit": 0, - "unit_amount": "string", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", }, - ] + ], }, + model_type="max_group_tiered_package", + name="Annual fee", ) assert response.is_closed is True @@ -1835,29 +7097,27 @@ async def test_raw_response_create_overload_5(self, async_client: AsyncOrb) -> N assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_5(self, async_client: AsyncOrb) -> None: + async def test_streaming_response_create_overload_25(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered", - name="Annual fee", - tiered_config={ + currency="currency", + item_id="item_id", + max_group_tiered_package_config={ + "grouping_key": "x", + "package_size": "package_size", "tiers": [ { - "first_unit": 0, - "unit_amount": "string", - }, - { - "first_unit": 0, - "unit_amount": "string", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", }, { - "first_unit": 0, - "unit_amount": "string", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", }, - ] + ], }, + model_type="max_group_tiered_package", + name="Annual fee", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1868,93 +7128,93 @@ async def test_streaming_response_create_overload_5(self, async_client: AsyncOrb assert cast(Any, response.is_closed) is True @parametrize - async def test_method_create_overload_6(self, async_client: AsyncOrb) -> None: + async def test_method_create_overload_26(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_bps", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_unit_pricing", name="Annual fee", - tiered_bps_config={ - "tiers": [ - { - "minimum_amount": "string", - "bps": 0, - }, + scalable_matrix_with_unit_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ { - "minimum_amount": "string", - "bps": 0, - }, - { - "minimum_amount": "string", - "bps": 0, - }, - ] + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + } + ], + "unit_price": "unit_price", }, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_6(self, async_client: AsyncOrb) -> None: + async def test_method_create_with_all_params_overload_26(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_bps", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_unit_pricing", name="Annual fee", - tiered_bps_config={ - "tiers": [ - { - "minimum_amount": "string", - "maximum_amount": "string", - "bps": 0, - "per_unit_maximum": "string", - }, - { - "minimum_amount": "string", - "maximum_amount": "string", - "bps": 0, - "per_unit_maximum": "string", - }, + scalable_matrix_with_unit_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ { - "minimum_amount": "string", - "maximum_amount": "string", - "bps": 0, - "per_unit_maximum": "string", - }, - ] + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + "second_dimension_value": "second_dimension_value", + } + ], + "unit_price": "unit_price", + "grouping_key": "x", + "prorate": True, + "second_dimension": "second_dimension", }, - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_6(self, async_client: AsyncOrb) -> None: + async def test_raw_response_create_overload_26(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_bps", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_unit_pricing", name="Annual fee", - tiered_bps_config={ - "tiers": [ - { - "minimum_amount": "string", - "bps": 0, - }, - { - "minimum_amount": "string", - "bps": 0, - }, + scalable_matrix_with_unit_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ { - "minimum_amount": "string", - "bps": 0, - }, - ] + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + } + ], + "unit_price": "unit_price", }, ) @@ -1964,28 +7224,22 @@ async def test_raw_response_create_overload_6(self, async_client: AsyncOrb) -> N assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_6(self, async_client: AsyncOrb) -> None: + async def test_streaming_response_create_overload_26(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_bps", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_unit_pricing", name="Annual fee", - tiered_bps_config={ - "tiers": [ - { - "minimum_amount": "string", - "bps": 0, - }, - { - "minimum_amount": "string", - "bps": 0, - }, + scalable_matrix_with_unit_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ { - "minimum_amount": "string", - "bps": 0, - }, - ] + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + } + ], + "unit_price": "unit_price", }, ) as response: assert not response.is_closed @@ -1997,46 +7251,119 @@ async def test_streaming_response_create_overload_6(self, async_client: AsyncOrb assert cast(Any, response.is_closed) is True @parametrize - async def test_method_create_overload_7(self, async_client: AsyncOrb) -> None: + async def test_method_create_overload_27(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( - bps_config={"bps": 0}, cadence="annual", - currency="string", - item_id="string", - model_type="bps", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_tiered_pricing", name="Annual fee", + scalable_matrix_with_tiered_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ + { + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + } + ], + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_7(self, async_client: AsyncOrb) -> None: + async def test_method_create_with_all_params_overload_27(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( - bps_config={ - "bps": 0, - "per_unit_maximum": "string", - }, cadence="annual", - currency="string", - item_id="string", - model_type="bps", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_tiered_pricing", name="Annual fee", - billable_metric_id="string", + scalable_matrix_with_tiered_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ + { + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + "second_dimension_value": "second_dimension_value", + } + ], + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + "second_dimension": "second_dimension", + }, + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_7(self, async_client: AsyncOrb) -> None: + async def test_raw_response_create_overload_27(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.create( - bps_config={"bps": 0}, cadence="annual", - currency="string", - item_id="string", - model_type="bps", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_tiered_pricing", name="Annual fee", + scalable_matrix_with_tiered_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ + { + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + } + ], + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, ) assert response.is_closed is True @@ -2045,14 +7372,32 @@ async def test_raw_response_create_overload_7(self, async_client: AsyncOrb) -> N assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_7(self, async_client: AsyncOrb) -> None: + async def test_streaming_response_create_overload_27(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.create( - bps_config={"bps": 0}, cadence="annual", - currency="string", - item_id="string", - model_type="bps", + currency="currency", + item_id="item_id", + model_type="scalable_matrix_with_tiered_pricing", name="Annual fee", + scalable_matrix_with_tiered_pricing_config={ + "first_dimension": "first_dimension", + "matrix_scaling_factors": [ + { + "first_dimension_value": "first_dimension_value", + "scaling_factor": "scaling_factor", + } + ], + "tiers": [ + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + { + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + }, + ], + }, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -2063,60 +7408,89 @@ async def test_streaming_response_create_overload_7(self, async_client: AsyncOrb assert cast(Any, response.is_closed) is True @parametrize - async def test_method_create_overload_8(self, async_client: AsyncOrb) -> None: + async def test_method_create_overload_28(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( - bulk_bps_config={"tiers": [{"bps": 0}, {"bps": 0}, {"bps": 0}]}, cadence="annual", - currency="string", - item_id="string", - model_type="bulk_bps", + cumulative_grouped_bulk_config={ + "dimension_values": [ + { + "grouping_key": "x", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + } + ], + "group": "group", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", name="Annual fee", ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_8(self, async_client: AsyncOrb) -> None: + async def test_method_create_with_all_params_overload_28(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( - bulk_bps_config={ - "tiers": [ - { - "maximum_amount": "string", - "bps": 0, - "per_unit_maximum": "string", - }, - { - "maximum_amount": "string", - "bps": 0, - "per_unit_maximum": "string", - }, + cadence="annual", + cumulative_grouped_bulk_config={ + "dimension_values": [ { - "maximum_amount": "string", - "bps": 0, - "per_unit_maximum": "string", - }, - ] + "grouping_key": "x", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + } + ], + "group": "group", }, - cadence="annual", - currency="string", - item_id="string", - model_type="bulk_bps", + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", name="Annual fee", - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_8(self, async_client: AsyncOrb) -> None: + async def test_raw_response_create_overload_28(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.create( - bulk_bps_config={"tiers": [{"bps": 0}, {"bps": 0}, {"bps": 0}]}, cadence="annual", - currency="string", - item_id="string", - model_type="bulk_bps", + cumulative_grouped_bulk_config={ + "dimension_values": [ + { + "grouping_key": "x", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + } + ], + "group": "group", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", name="Annual fee", ) @@ -2126,13 +7500,22 @@ async def test_raw_response_create_overload_8(self, async_client: AsyncOrb) -> N assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_8(self, async_client: AsyncOrb) -> None: + async def test_streaming_response_create_overload_28(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.create( - bulk_bps_config={"tiers": [{"bps": 0}, {"bps": 0}, {"bps": 0}]}, cadence="annual", - currency="string", - item_id="string", - model_type="bulk_bps", + cumulative_grouped_bulk_config={ + "dimension_values": [ + { + "grouping_key": "x", + "tier_lower_bound": "tier_lower_bound", + "unit_amount": "unit_amount", + } + ], + "group": "group", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_bulk", name="Annual fee", ) as response: assert not response.is_closed @@ -2144,57 +7527,77 @@ async def test_streaming_response_create_overload_8(self, async_client: AsyncOrb assert cast(Any, response.is_closed) is True @parametrize - async def test_method_create_overload_9(self, async_client: AsyncOrb) -> None: + async def test_method_create_overload_29(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( - bulk_config={"tiers": [{"unit_amount": "string"}, {"unit_amount": "string"}, {"unit_amount": "string"}]}, cadence="annual", - currency="string", - item_id="string", - model_type="bulk", + cumulative_grouped_allocation_config={ + "cumulative_allocation": "cumulative_allocation", + "group_allocation": "group_allocation", + "grouping_key": "x", + "unit_amount": "unit_amount", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_allocation", name="Annual fee", ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_9(self, async_client: AsyncOrb) -> None: + async def test_method_create_with_all_params_overload_29(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( - bulk_config={ - "tiers": [ - { - "maximum_units": 0, - "unit_amount": "string", - }, - { - "maximum_units": 0, - "unit_amount": "string", - }, - { - "maximum_units": 0, - "unit_amount": "string", - }, - ] - }, cadence="annual", - currency="string", - item_id="string", - model_type="bulk", + cumulative_grouped_allocation_config={ + "cumulative_allocation": "cumulative_allocation", + "group_allocation": "group_allocation", + "grouping_key": "x", + "unit_amount": "unit_amount", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_allocation", name="Annual fee", - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_9(self, async_client: AsyncOrb) -> None: + async def test_raw_response_create_overload_29(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.create( - bulk_config={"tiers": [{"unit_amount": "string"}, {"unit_amount": "string"}, {"unit_amount": "string"}]}, cadence="annual", - currency="string", - item_id="string", - model_type="bulk", + cumulative_grouped_allocation_config={ + "cumulative_allocation": "cumulative_allocation", + "group_allocation": "group_allocation", + "grouping_key": "x", + "unit_amount": "unit_amount", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_allocation", name="Annual fee", ) @@ -2204,13 +7607,18 @@ async def test_raw_response_create_overload_9(self, async_client: AsyncOrb) -> N assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_9(self, async_client: AsyncOrb) -> None: + async def test_streaming_response_create_overload_29(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.create( - bulk_config={"tiers": [{"unit_amount": "string"}, {"unit_amount": "string"}, {"unit_amount": "string"}]}, cadence="annual", - currency="string", - item_id="string", - model_type="bulk", + cumulative_grouped_allocation_config={ + "cumulative_allocation": "cumulative_allocation", + "group_allocation": "group_allocation", + "grouping_key": "x", + "unit_amount": "unit_amount", + }, + currency="currency", + item_id="item_id", + model_type="cumulative_grouped_allocation", name="Annual fee", ) as response: assert not response.is_closed @@ -2222,43 +7630,96 @@ async def test_streaming_response_create_overload_9(self, async_client: AsyncOrb assert cast(Any, response.is_closed) is True @parametrize - async def test_method_create_overload_10(self, async_client: AsyncOrb) -> None: + async def test_method_create_overload_30(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="threshold_total_amount", + currency="currency", + daily_credit_allowance_config={ + "daily_allowance": "daily_allowance", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "event_day_property": "x", + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + item_id="item_id", + model_type="daily_credit_allowance", name="Annual fee", - threshold_total_amount_config={"foo": "bar"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_10(self, async_client: AsyncOrb) -> None: + async def test_method_create_with_all_params_overload_30(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="threshold_total_amount", + currency="currency", + daily_credit_allowance_config={ + "daily_allowance": "daily_allowance", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "event_day_property": "x", + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + item_id="item_id", + model_type="daily_credit_allowance", name="Annual fee", - threshold_total_amount_config={"foo": "bar"}, - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_10(self, async_client: AsyncOrb) -> None: + async def test_raw_response_create_overload_30(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="threshold_total_amount", + currency="currency", + daily_credit_allowance_config={ + "daily_allowance": "daily_allowance", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "event_day_property": "x", + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + item_id="item_id", + model_type="daily_credit_allowance", name="Annual fee", - threshold_total_amount_config={"foo": "bar"}, ) assert response.is_closed is True @@ -2267,14 +7728,25 @@ async def test_raw_response_create_overload_10(self, async_client: AsyncOrb) -> assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_10(self, async_client: AsyncOrb) -> None: + async def test_streaming_response_create_overload_30(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="threshold_total_amount", + currency="currency", + daily_credit_allowance_config={ + "daily_allowance": "daily_allowance", + "default_unit_amount": "default_unit_amount", + "dimensions": ["string"], + "event_day_property": "x", + "matrix_values": [ + { + "dimension_values": ["string"], + "unit_amount": "unit_amount", + } + ], + }, + item_id="item_id", + model_type="daily_credit_allowance", name="Annual fee", - threshold_total_amount_config={"foo": "bar"}, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -2285,43 +7757,80 @@ async def test_streaming_response_create_overload_10(self, async_client: AsyncOr assert cast(Any, response.is_closed) is True @parametrize - async def test_method_create_overload_11(self, async_client: AsyncOrb) -> None: + async def test_method_create_overload_31(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package", + currency="currency", + item_id="item_id", + metered_allowance_config={ + "allowance_grouping_value": "x", + "consumption_grouping_value": "x", + "grouping_key": "x", + "unit_amount": "unit_amount", + }, + model_type="metered_allowance", name="Annual fee", - tiered_package_config={"foo": "bar"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_11(self, async_client: AsyncOrb) -> None: + async def test_method_create_with_all_params_overload_31(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package", + currency="currency", + item_id="item_id", + metered_allowance_config={ + "allowance_grouping_value": "x", + "consumption_grouping_value": "x", + "grouping_key": "x", + "unit_amount": "unit_amount", + "allowance_display_name": "x", + "consumption_display_name": "x", + }, + model_type="metered_allowance", name="Annual fee", - tiered_package_config={"foo": "bar"}, - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_11(self, async_client: AsyncOrb) -> None: + async def test_raw_response_create_overload_31(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package", + currency="currency", + item_id="item_id", + metered_allowance_config={ + "allowance_grouping_value": "x", + "consumption_grouping_value": "x", + "grouping_key": "x", + "unit_amount": "unit_amount", + }, + model_type="metered_allowance", name="Annual fee", - tiered_package_config={"foo": "bar"}, ) assert response.is_closed is True @@ -2330,14 +7839,19 @@ async def test_raw_response_create_overload_11(self, async_client: AsyncOrb) -> assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_11(self, async_client: AsyncOrb) -> None: + async def test_streaming_response_create_overload_31(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package", + currency="currency", + item_id="item_id", + metered_allowance_config={ + "allowance_grouping_value": "x", + "consumption_grouping_value": "x", + "grouping_key": "x", + "unit_amount": "unit_amount", + }, + model_type="metered_allowance", name="Annual fee", - tiered_package_config={"foo": "bar"}, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -2348,43 +7862,66 @@ async def test_streaming_response_create_overload_11(self, async_client: AsyncOr assert cast(Any, response.is_closed) is True @parametrize - async def test_method_create_overload_12(self, async_client: AsyncOrb) -> None: + async def test_method_create_overload_32(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_with_minimum", + currency="currency", + item_id="item_id", + minimum_composite_config={"minimum_amount": "minimum_amount"}, + model_type="minimum_composite", name="Annual fee", - tiered_with_minimum_config={"foo": "bar"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_12(self, async_client: AsyncOrb) -> None: + async def test_method_create_with_all_params_overload_32(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_with_minimum", + currency="currency", + item_id="item_id", + minimum_composite_config={ + "minimum_amount": "minimum_amount", + "prorated": True, + }, + model_type="minimum_composite", name="Annual fee", - tiered_with_minimum_config={"foo": "bar"}, - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_12(self, async_client: AsyncOrb) -> None: + async def test_raw_response_create_overload_32(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_with_minimum", + currency="currency", + item_id="item_id", + minimum_composite_config={"minimum_amount": "minimum_amount"}, + model_type="minimum_composite", name="Annual fee", - tiered_with_minimum_config={"foo": "bar"}, ) assert response.is_closed is True @@ -2393,14 +7930,14 @@ async def test_raw_response_create_overload_12(self, async_client: AsyncOrb) -> assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_12(self, async_client: AsyncOrb) -> None: + async def test_streaming_response_create_overload_32(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_with_minimum", + currency="currency", + item_id="item_id", + minimum_composite_config={"minimum_amount": "minimum_amount"}, + model_type="minimum_composite", name="Annual fee", - tiered_with_minimum_config={"foo": "bar"}, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -2411,43 +7948,68 @@ async def test_streaming_response_create_overload_12(self, async_client: AsyncOr assert cast(Any, response.is_closed) is True @parametrize - async def test_method_create_overload_13(self, async_client: AsyncOrb) -> None: + async def test_method_create_overload_33(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="package_with_allocation", + currency="currency", + item_id="item_id", + model_type="percent", name="Annual fee", - package_with_allocation_config={"foo": "bar"}, + percent_config={"percent": 1}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_13(self, async_client: AsyncOrb) -> None: + async def test_method_create_with_all_params_overload_33(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="package_with_allocation", + currency="currency", + item_id="item_id", + model_type="percent", name="Annual fee", - package_with_allocation_config={"foo": "bar"}, - billable_metric_id="string", + percent_config={ + "percent": 1, + "maximum_amount": "maximum_amount", + "minimum_amount": "minimum_amount", + "prorated": True, + }, + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_13(self, async_client: AsyncOrb) -> None: + async def test_raw_response_create_overload_33(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="package_with_allocation", + currency="currency", + item_id="item_id", + model_type="percent", name="Annual fee", - package_with_allocation_config={"foo": "bar"}, + percent_config={"percent": 1}, ) assert response.is_closed is True @@ -2456,14 +8018,14 @@ async def test_raw_response_create_overload_13(self, async_client: AsyncOrb) -> assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_13(self, async_client: AsyncOrb) -> None: + async def test_streaming_response_create_overload_33(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="package_with_allocation", + currency="currency", + item_id="item_id", + model_type="percent", name="Annual fee", - package_with_allocation_config={"foo": "bar"}, + percent_config={"percent": 1}, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -2474,43 +8036,67 @@ async def test_streaming_response_create_overload_13(self, async_client: AsyncOr assert cast(Any, response.is_closed) is True @parametrize - async def test_method_create_overload_14(self, async_client: AsyncOrb) -> None: + async def test_method_create_overload_34(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package_with_minimum", + currency="currency", + event_output_config={"unit_rating_key": "x"}, + item_id="item_id", + model_type="event_output", name="Annual fee", - tiered_package_with_minimum_config={"foo": "bar"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_14(self, async_client: AsyncOrb) -> None: + async def test_method_create_with_all_params_overload_34(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package_with_minimum", + currency="currency", + event_output_config={ + "unit_rating_key": "x", + "default_unit_rate": "default_unit_rate", + "grouping_key": "grouping_key", + }, + item_id="item_id", + model_type="event_output", name="Annual fee", - tiered_package_with_minimum_config={"foo": "bar"}, - billable_metric_id="string", + billable_metric_id="billable_metric_id", billed_in_advance=True, - external_price_id="string", + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + conversion_rate_config={ + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + dimensional_price_configuration={ + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + external_price_id="external_price_id", fixed_price_quantity=0, - invoice_grouping_key="string", + invoice_grouping_key="x", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + license_type_id="license_type_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_14(self, async_client: AsyncOrb) -> None: + async def test_raw_response_create_overload_34(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package_with_minimum", + currency="currency", + event_output_config={"unit_rating_key": "x"}, + item_id="item_id", + model_type="event_output", name="Annual fee", - tiered_package_with_minimum_config={"foo": "bar"}, ) assert response.is_closed is True @@ -2519,14 +8105,14 @@ async def test_raw_response_create_overload_14(self, async_client: AsyncOrb) -> assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_14(self, async_client: AsyncOrb) -> None: + async def test_streaming_response_create_overload_34(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.create( cadence="annual", - currency="string", - item_id="string", - model_type="tiered_package_with_minimum", + currency="currency", + event_output_config={"unit_rating_key": "x"}, + item_id="item_id", + model_type="event_output", name="Annual fee", - tiered_package_with_minimum_config={"foo": "bar"}, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -2537,43 +8123,24 @@ async def test_streaming_response_create_overload_14(self, async_client: AsyncOr assert cast(Any, response.is_closed) is True @parametrize - async def test_method_create_overload_15(self, async_client: AsyncOrb) -> None: - price = await async_client.prices.create( - cadence="annual", - currency="string", - item_id="string", - model_type="unit_with_percent", - name="Annual fee", - unit_with_percent_config={"foo": "bar"}, + async def test_method_update(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.update( + price_id="price_id", ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_15(self, async_client: AsyncOrb) -> None: - price = await async_client.prices.create( - cadence="annual", - currency="string", - item_id="string", - model_type="unit_with_percent", - name="Annual fee", - unit_with_percent_config={"foo": "bar"}, - billable_metric_id="string", - billed_in_advance=True, - external_price_id="string", - fixed_price_quantity=0, - invoice_grouping_key="string", + async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.update( + price_id="price_id", + metadata={"foo": "string"}, ) assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_15(self, async_client: AsyncOrb) -> None: - response = await async_client.prices.with_raw_response.create( - cadence="annual", - currency="string", - item_id="string", - model_type="unit_with_percent", - name="Annual fee", - unit_with_percent_config={"foo": "bar"}, + async def test_raw_response_update(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.update( + price_id="price_id", ) assert response.is_closed is True @@ -2582,14 +8149,9 @@ async def test_raw_response_create_overload_15(self, async_client: AsyncOrb) -> assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_15(self, async_client: AsyncOrb) -> None: - async with async_client.prices.with_streaming_response.create( - cadence="annual", - currency="string", - item_id="string", - model_type="unit_with_percent", - name="Annual fee", - unit_with_percent_config={"foo": "bar"}, + async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.update( + price_id="price_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -2599,6 +8161,13 @@ async def test_streaming_response_create_overload_15(self, async_client: AsyncOr assert cast(Any, response.is_closed) is True + @parametrize + async def test_path_params_update(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `price_id` but received ''"): + await async_client.prices.with_raw_response.update( + price_id="", + ) + @parametrize async def test_method_list(self, async_client: AsyncOrb) -> None: price = await async_client.prices.list() @@ -2607,8 +8176,8 @@ async def test_method_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: price = await async_client.prices.list( - cursor="string", - limit=0, + cursor="cursor", + limit=1, ) assert_matches_type(AsyncPage[Price], price, path=["response"]) @@ -2632,17 +8201,264 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_evaluate(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.evaluate( + price_id="price_id", + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(PriceEvaluateResponse, price, path=["response"]) + + @parametrize + async def test_method_evaluate_with_all_params(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.evaluate( + price_id="price_id", + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + customer_id="customer_id", + external_customer_id="external_customer_id", + filter="my_numeric_property > 100 AND my_other_property = 'bar'", + grouping_keys=["case when my_event_type = 'foo' then true else false end"], + metric_parameter_overrides={"foo": "bar"}, + ) + assert_matches_type(PriceEvaluateResponse, price, path=["response"]) + + @parametrize + async def test_raw_response_evaluate(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.evaluate( + price_id="price_id", + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" + price = response.parse() + assert_matches_type(PriceEvaluateResponse, price, path=["response"]) + + @parametrize + async def test_streaming_response_evaluate(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.evaluate( + price_id="price_id", + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" + + price = await response.parse() + assert_matches_type(PriceEvaluateResponse, price, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_evaluate(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `price_id` but received ''"): + await async_client.prices.with_raw_response.evaluate( + price_id="", + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + + @parametrize + async def test_method_evaluate_multiple(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.evaluate_multiple( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(PriceEvaluateMultipleResponse, price, path=["response"]) + + @parametrize + async def test_method_evaluate_multiple_with_all_params(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.evaluate_multiple( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + customer_id="customer_id", + external_customer_id="external_customer_id", + price_evaluations=[ + { + "external_price_id": "external_price_id", + "filter": "my_numeric_property > 100 AND my_other_property = 'bar'", + "grouping_keys": ["case when my_event_type = 'foo' then true else false end"], + "metric_parameter_overrides": {"foo": "bar"}, + "price": { + "cadence": "annual", + "currency": "currency", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + }, + "price_id": "price_id", + } + ], + ) + assert_matches_type(PriceEvaluateMultipleResponse, price, path=["response"]) + + @parametrize + async def test_raw_response_evaluate_multiple(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.evaluate_multiple( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" + price = response.parse() + assert_matches_type(PriceEvaluateMultipleResponse, price, path=["response"]) + + @parametrize + async def test_streaming_response_evaluate_multiple(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.evaluate_multiple( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" + + price = await response.parse() + assert_matches_type(PriceEvaluateMultipleResponse, price, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_evaluate_preview_events(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.evaluate_preview_events( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(PriceEvaluatePreviewEventsResponse, price, path=["response"]) + + @parametrize + async def test_method_evaluate_preview_events_with_all_params(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.evaluate_preview_events( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + customer_id="customer_id", + events=[ + { + "event_name": "event_name", + "properties": {"foo": "bar"}, + "timestamp": parse_datetime("2020-12-09T16:09:53Z"), + "customer_id": "customer_id", + "external_customer_id": "external_customer_id", + } + ], + external_customer_id="external_customer_id", + price_evaluations=[ + { + "external_price_id": "external_price_id", + "filter": "my_numeric_property > 100 AND my_other_property = 'bar'", + "grouping_keys": ["case when my_event_type = 'foo' then true else false end"], + "metric_parameter_overrides": {"foo": "bar"}, + "price": { + "cadence": "annual", + "currency": "currency", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + }, + "price_id": "price_id", + } + ], + ) + assert_matches_type(PriceEvaluatePreviewEventsResponse, price, path=["response"]) + + @parametrize + async def test_raw_response_evaluate_preview_events(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.evaluate_preview_events( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" + price = response.parse() + assert_matches_type(PriceEvaluatePreviewEventsResponse, price, path=["response"]) + + @parametrize + async def test_streaming_response_evaluate_preview_events(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.evaluate_preview_events( + timeframe_end=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" + + price = await response.parse() + assert_matches_type(PriceEvaluatePreviewEventsResponse, price, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_fetch(self, async_client: AsyncOrb) -> None: price = await async_client.prices.fetch( - "string", + "price_id", ) assert_matches_type(Price, price, path=["response"]) @parametrize async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.fetch( - "string", + "price_id", ) assert response.is_closed is True @@ -2653,7 +8469,7 @@ async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_fetch(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.fetch( - "string", + "price_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/test_subscription_changes.py b/tests/api_resources/test_subscription_changes.py new file mode 100644 index 00000000..0a5d6dae --- /dev/null +++ b/tests/api_resources/test_subscription_changes.py @@ -0,0 +1,369 @@ +# 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.types import ( + SubscriptionChangeListResponse, + SubscriptionChangeApplyResponse, + SubscriptionChangeCancelResponse, + SubscriptionChangeRetrieveResponse, +) +from orb._utils import parse_date +from tests.utils import assert_matches_type +from orb.pagination import SyncPage, AsyncPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSubscriptionChanges: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: Orb) -> None: + subscription_change = client.subscription_changes.retrieve( + "subscription_change_id", + ) + assert_matches_type(SubscriptionChangeRetrieveResponse, subscription_change, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: Orb) -> None: + response = client.subscription_changes.with_raw_response.retrieve( + "subscription_change_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription_change = response.parse() + assert_matches_type(SubscriptionChangeRetrieveResponse, subscription_change, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: Orb) -> None: + with client.subscription_changes.with_streaming_response.retrieve( + "subscription_change_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subscription_change = response.parse() + assert_matches_type(SubscriptionChangeRetrieveResponse, subscription_change, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: Orb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `subscription_change_id` but received ''" + ): + client.subscription_changes.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_list(self, client: Orb) -> None: + subscription_change = client.subscription_changes.list() + assert_matches_type(SyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Orb) -> None: + subscription_change = client.subscription_changes.list( + cursor="cursor", + customer_id="customer_id", + external_customer_id="external_customer_id", + limit=1, + status="pending", + ) + assert_matches_type(SyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Orb) -> None: + response = client.subscription_changes.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription_change = response.parse() + assert_matches_type(SyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Orb) -> None: + with client.subscription_changes.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subscription_change = response.parse() + assert_matches_type(SyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_apply(self, client: Orb) -> None: + subscription_change = client.subscription_changes.apply( + subscription_change_id="subscription_change_id", + ) + assert_matches_type(SubscriptionChangeApplyResponse, subscription_change, path=["response"]) + + @parametrize + def test_method_apply_with_all_params(self, client: Orb) -> None: + subscription_change = client.subscription_changes.apply( + subscription_change_id="subscription_change_id", + description="description", + mark_as_paid=True, + payment_external_id="payment_external_id", + payment_notes="payment_notes", + payment_received_date=parse_date("2019-12-27"), + previously_collected_amount="previously_collected_amount", + ) + assert_matches_type(SubscriptionChangeApplyResponse, subscription_change, path=["response"]) + + @parametrize + def test_raw_response_apply(self, client: Orb) -> None: + response = client.subscription_changes.with_raw_response.apply( + subscription_change_id="subscription_change_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription_change = response.parse() + assert_matches_type(SubscriptionChangeApplyResponse, subscription_change, path=["response"]) + + @parametrize + def test_streaming_response_apply(self, client: Orb) -> None: + with client.subscription_changes.with_streaming_response.apply( + subscription_change_id="subscription_change_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subscription_change = response.parse() + assert_matches_type(SubscriptionChangeApplyResponse, subscription_change, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_apply(self, client: Orb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `subscription_change_id` but received ''" + ): + client.subscription_changes.with_raw_response.apply( + subscription_change_id="", + ) + + @parametrize + def test_method_cancel(self, client: Orb) -> None: + subscription_change = client.subscription_changes.cancel( + "subscription_change_id", + ) + assert_matches_type(SubscriptionChangeCancelResponse, subscription_change, path=["response"]) + + @parametrize + def test_raw_response_cancel(self, client: Orb) -> None: + response = client.subscription_changes.with_raw_response.cancel( + "subscription_change_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription_change = response.parse() + assert_matches_type(SubscriptionChangeCancelResponse, subscription_change, path=["response"]) + + @parametrize + def test_streaming_response_cancel(self, client: Orb) -> None: + with client.subscription_changes.with_streaming_response.cancel( + "subscription_change_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subscription_change = response.parse() + assert_matches_type(SubscriptionChangeCancelResponse, subscription_change, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_cancel(self, client: Orb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `subscription_change_id` but received ''" + ): + client.subscription_changes.with_raw_response.cancel( + "", + ) + + +class TestAsyncSubscriptionChanges: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOrb) -> None: + subscription_change = await async_client.subscription_changes.retrieve( + "subscription_change_id", + ) + assert_matches_type(SubscriptionChangeRetrieveResponse, subscription_change, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOrb) -> None: + response = await async_client.subscription_changes.with_raw_response.retrieve( + "subscription_change_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription_change = response.parse() + assert_matches_type(SubscriptionChangeRetrieveResponse, subscription_change, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOrb) -> None: + async with async_client.subscription_changes.with_streaming_response.retrieve( + "subscription_change_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subscription_change = await response.parse() + assert_matches_type(SubscriptionChangeRetrieveResponse, subscription_change, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOrb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `subscription_change_id` but received ''" + ): + await async_client.subscription_changes.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOrb) -> None: + subscription_change = await async_client.subscription_changes.list() + assert_matches_type(AsyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: + subscription_change = await async_client.subscription_changes.list( + cursor="cursor", + customer_id="customer_id", + external_customer_id="external_customer_id", + limit=1, + status="pending", + ) + assert_matches_type(AsyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOrb) -> None: + response = await async_client.subscription_changes.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription_change = response.parse() + assert_matches_type(AsyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: + async with async_client.subscription_changes.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subscription_change = await response.parse() + assert_matches_type(AsyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_apply(self, async_client: AsyncOrb) -> None: + subscription_change = await async_client.subscription_changes.apply( + subscription_change_id="subscription_change_id", + ) + assert_matches_type(SubscriptionChangeApplyResponse, subscription_change, path=["response"]) + + @parametrize + async def test_method_apply_with_all_params(self, async_client: AsyncOrb) -> None: + subscription_change = await async_client.subscription_changes.apply( + subscription_change_id="subscription_change_id", + description="description", + mark_as_paid=True, + payment_external_id="payment_external_id", + payment_notes="payment_notes", + payment_received_date=parse_date("2019-12-27"), + previously_collected_amount="previously_collected_amount", + ) + assert_matches_type(SubscriptionChangeApplyResponse, subscription_change, path=["response"]) + + @parametrize + async def test_raw_response_apply(self, async_client: AsyncOrb) -> None: + response = await async_client.subscription_changes.with_raw_response.apply( + subscription_change_id="subscription_change_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription_change = response.parse() + assert_matches_type(SubscriptionChangeApplyResponse, subscription_change, path=["response"]) + + @parametrize + async def test_streaming_response_apply(self, async_client: AsyncOrb) -> None: + async with async_client.subscription_changes.with_streaming_response.apply( + subscription_change_id="subscription_change_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subscription_change = await response.parse() + assert_matches_type(SubscriptionChangeApplyResponse, subscription_change, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_apply(self, async_client: AsyncOrb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `subscription_change_id` but received ''" + ): + await async_client.subscription_changes.with_raw_response.apply( + subscription_change_id="", + ) + + @parametrize + async def test_method_cancel(self, async_client: AsyncOrb) -> None: + subscription_change = await async_client.subscription_changes.cancel( + "subscription_change_id", + ) + assert_matches_type(SubscriptionChangeCancelResponse, subscription_change, path=["response"]) + + @parametrize + async def test_raw_response_cancel(self, async_client: AsyncOrb) -> None: + response = await async_client.subscription_changes.with_raw_response.cancel( + "subscription_change_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription_change = response.parse() + assert_matches_type(SubscriptionChangeCancelResponse, subscription_change, path=["response"]) + + @parametrize + async def test_streaming_response_cancel(self, async_client: AsyncOrb) -> None: + async with async_client.subscription_changes.with_streaming_response.cancel( + "subscription_change_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subscription_change = await response.parse() + assert_matches_type(SubscriptionChangeCancelResponse, subscription_change, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_cancel(self, async_client: AsyncOrb) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `subscription_change_id` but received ''" + ): + await async_client.subscription_changes.with_raw_response.cancel( + "", + ) diff --git a/tests/api_resources/test_subscriptions.py b/tests/api_resources/test_subscriptions.py index a71d3e28..e7394de7 100644 --- a/tests/api_resources/test_subscriptions.py +++ b/tests/api_resources/test_subscriptions.py @@ -11,6 +11,7 @@ from orb.types import ( Subscription, SubscriptionUsage, + MutatedSubscription, SubscriptionFetchCostsResponse, SubscriptionFetchScheduleResponse, ) @@ -27,82 +28,253 @@ 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(MutatedSubscription, 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", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "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=[ + { + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "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", + "metric_parameter_overrides": {"foo": "bar"}, + "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", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "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="string", - coupon_redemption_code="string", + auto_issuance=True, + aws_region="aws_region", + billing_cycle_anchor_configuration={ + "day": 1, + "month": 1, + "year": 0, + }, + coupon_redemption_code="coupon_redemption_code", credits_overage_rate=0, - customer_id="string", - default_invoice_memo="string", + currency="currency", + customer_id="customer_id", + default_invoice_memo="default_invoice_memo", end_date=parse_datetime("2019-12-27T18:11:19.117Z"), - external_customer_id="string", + external_customer_id="external_customer_id", external_marketplace="google", - external_marketplace_reporting_id="string", + external_marketplace_reporting_id="external_marketplace_reporting_id", external_plan_id="ZMwNQefe7J3ecf7W", - initial_phase_order=0, - invoicing_threshold="string", + filter="my_property > 100 AND my_other_property = 'bar'", + initial_phase_order=2, + invoicing_threshold="10.00", metadata={"foo": "string"}, + name="name", net_terms=0, - per_credit_overage_amount="string", + per_credit_overage_amount=0, plan_id="ZMwNQefe7J3ecf7W", - price_overrides=[ + plan_version_number=0, + price_overrides=[{}], + remove_adjustments=[{"adjustment_id": "h74gfhdjvn7ujokd"}], + remove_prices=[ { - "id": "string", - "model_type": "unit", - "minimum_amount": "1.23", - "maximum_amount": "1.23", - "discount": { - "discount_type": "percentage", - "percentage_discount": 0.15, - "trial_amount_discount": "string", - "usage_discount": 0, - "amount_discount": "string", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + "external_price_id": "external_price_id", + "price_id": "h74gfhdjvn7ujokd", + } + ], + replace_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", }, - "fixed_price_quantity": 2, - "unit_config": {"unit_amount": "string"}, - }, + "replaces_adjustment_id": "replaces_adjustment_id", + } + ], + replace_prices=[ { - "id": "string", - "model_type": "unit", - "minimum_amount": "1.23", - "maximum_amount": "1.23", - "discount": { - "discount_type": "percentage", - "percentage_discount": 0.15, - "trial_amount_discount": "string", - "usage_discount": 0, - "amount_discount": "string", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + "replaces_price_id": "replaces_price_id", + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", }, + "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, - "unit_config": {"unit_amount": "string"}, - }, - { - "id": "string", - "model_type": "unit", - "minimum_amount": "1.23", "maximum_amount": "1.23", - "discount": { - "discount_type": "percentage", - "percentage_discount": 0.15, - "trial_amount_discount": "string", - "usage_discount": 0, - "amount_discount": "string", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + "metric_parameter_overrides": {"foo": "bar"}, + "minimum_amount": "1.23", + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", }, - "fixed_price_quantity": 2, - "unit_config": {"unit_amount": "string"}, - }, + "price_id": "h74gfhdjvn7ujokd", + } ], start_date=parse_datetime("2019-12-27T18:11:19.117Z"), + trial_duration_days=0, + usage_customer_ids=["string"], ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_raw_response_create(self, client: Orb) -> None: @@ -111,7 +283,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(MutatedSubscription, subscription, path=["response"]) @parametrize def test_streaming_response_create(self, client: Orb) -> None: @@ -119,11 +291,62 @@ def test_streaming_response_create(self, client: Orb) -> None: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription = response.parse() + assert_matches_type(MutatedSubscription, subscription, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Orb) -> None: + subscription = client.subscriptions.update( + subscription_id="subscription_id", + ) + assert_matches_type(Subscription, subscription, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Orb) -> None: + subscription = client.subscriptions.update( + subscription_id="subscription_id", + auto_collection=True, + auto_issuance=True, + default_invoice_memo="default_invoice_memo", + invoicing_threshold="10.00", + metadata={"foo": "string"}, + net_terms=0, + ) + assert_matches_type(Subscription, subscription, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Orb) -> None: + response = client.subscriptions.with_raw_response.update( + 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"]) + + @parametrize + def test_streaming_response_update(self, client: Orb) -> None: + with client.subscriptions.with_streaming_response.update( + 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 + @parametrize + def test_path_params_update(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( + subscription_id="", + ) + @parametrize def test_method_list(self, client: Orb) -> None: subscription = client.subscriptions.list() @@ -136,10 +359,12 @@ def test_method_list_with_all_params(self, client: Orb) -> None: created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), - cursor="string", - customer_id="string", - external_customer_id="string", - limit=0, + cursor="cursor", + customer_id=["string"], + external_customer_id=["string"], + external_plan_id="external_plan_id", + limit=1, + plan_id="plan_id", status="active", ) assert_matches_type(SyncPage[Subscription], subscription, path=["response"]) @@ -167,43 +392,44 @@ def test_streaming_response_list(self, client: Orb) -> None: @parametrize def test_method_cancel(self, client: Orb) -> None: subscription = client.subscriptions.cancel( - "string", + subscription_id="subscription_id", cancel_option="end_of_subscription_term", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_method_cancel_with_all_params(self, client: Orb) -> None: subscription = client.subscriptions.cancel( - "string", + subscription_id="subscription_id", cancel_option="end_of_subscription_term", + allow_invoice_credit_or_void=True, cancellation_date=parse_datetime("2019-12-27T18:11:19.117Z"), ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_raw_response_cancel(self, client: Orb) -> None: response = client.subscriptions.with_raw_response.cancel( - "string", + subscription_id="subscription_id", cancel_option="end_of_subscription_term", ) 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(MutatedSubscription, subscription, path=["response"]) @parametrize def test_streaming_response_cancel(self, client: Orb) -> None: with client.subscriptions.with_streaming_response.cancel( - "string", + subscription_id="subscription_id", cancel_option="end_of_subscription_term", ) 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(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -211,21 +437,21 @@ def test_streaming_response_cancel(self, client: Orb) -> None: def test_path_params_cancel(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.cancel( - "", + subscription_id="", cancel_option="end_of_subscription_term", ) @parametrize def test_method_fetch(self, client: Orb) -> None: subscription = client.subscriptions.fetch( - "string", + "subscription_id", ) assert_matches_type(Subscription, subscription, path=["response"]) @parametrize def test_raw_response_fetch(self, client: Orb) -> None: response = client.subscriptions.with_raw_response.fetch( - "string", + "subscription_id", ) assert response.is_closed is True @@ -236,7 +462,7 @@ def test_raw_response_fetch(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch(self, client: Orb) -> None: with client.subscriptions.with_streaming_response.fetch( - "string", + "subscription_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -256,14 +482,15 @@ def test_path_params_fetch(self, client: Orb) -> None: @parametrize def test_method_fetch_costs(self, client: Orb) -> None: subscription = client.subscriptions.fetch_costs( - "string", + subscription_id="subscription_id", ) assert_matches_type(SubscriptionFetchCostsResponse, subscription, path=["response"]) @parametrize def test_method_fetch_costs_with_all_params(self, client: Orb) -> None: subscription = client.subscriptions.fetch_costs( - "string", + subscription_id="subscription_id", + currency="currency", timeframe_end=parse_datetime("2022-03-01T05:00:00Z"), timeframe_start=parse_datetime("2022-02-01T05:00:00Z"), view_mode="periodic", @@ -273,7 +500,7 @@ def test_method_fetch_costs_with_all_params(self, client: Orb) -> None: @parametrize def test_raw_response_fetch_costs(self, client: Orb) -> None: response = client.subscriptions.with_raw_response.fetch_costs( - "string", + subscription_id="subscription_id", ) assert response.is_closed is True @@ -284,7 +511,7 @@ def test_raw_response_fetch_costs(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch_costs(self, client: Orb) -> None: with client.subscriptions.with_streaming_response.fetch_costs( - "string", + subscription_id="subscription_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -298,22 +525,22 @@ def test_streaming_response_fetch_costs(self, client: Orb) -> None: def test_path_params_fetch_costs(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.fetch_costs( - "", + subscription_id="", ) @parametrize def test_method_fetch_schedule(self, client: Orb) -> None: subscription = client.subscriptions.fetch_schedule( - "string", + subscription_id="subscription_id", ) assert_matches_type(SyncPage[SubscriptionFetchScheduleResponse], subscription, path=["response"]) @parametrize def test_method_fetch_schedule_with_all_params(self, client: Orb) -> None: subscription = client.subscriptions.fetch_schedule( - "string", - cursor="string", - limit=0, + subscription_id="subscription_id", + cursor="cursor", + limit=1, start_date_gt=parse_datetime("2019-12-27T18:11:19.117Z"), start_date_gte=parse_datetime("2019-12-27T18:11:19.117Z"), start_date_lt=parse_datetime("2019-12-27T18:11:19.117Z"), @@ -324,7 +551,7 @@ def test_method_fetch_schedule_with_all_params(self, client: Orb) -> None: @parametrize def test_raw_response_fetch_schedule(self, client: Orb) -> None: response = client.subscriptions.with_raw_response.fetch_schedule( - "string", + subscription_id="subscription_id", ) assert response.is_closed is True @@ -335,7 +562,7 @@ def test_raw_response_fetch_schedule(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch_schedule(self, client: Orb) -> None: with client.subscriptions.with_streaming_response.fetch_schedule( - "string", + subscription_id="subscription_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -349,14 +576,14 @@ def test_streaming_response_fetch_schedule(self, client: Orb) -> None: def test_path_params_fetch_schedule(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.fetch_schedule( - "", + subscription_id="", ) @pytest.mark.skip(reason="Incorrect example breaks Prism") @parametrize def test_method_fetch_usage(self, client: Orb) -> None: subscription = client.subscriptions.fetch_usage( - "string", + subscription_id="subscription_id", ) assert_matches_type(SubscriptionUsage, subscription, path=["response"]) @@ -364,16 +591,14 @@ def test_method_fetch_usage(self, client: Orb) -> None: @parametrize def test_method_fetch_usage_with_all_params(self, client: Orb) -> None: subscription = client.subscriptions.fetch_usage( - "string", - billable_metric_id="string", - cursor="string", - first_dimension_key="string", - first_dimension_value="string", + subscription_id="subscription_id", + billable_metric_id="billable_metric_id", + first_dimension_key="first_dimension_key", + first_dimension_value="first_dimension_value", granularity="day", - group_by="string", - limit=0, - second_dimension_key="string", - second_dimension_value="string", + group_by="group_by", + second_dimension_key="second_dimension_key", + second_dimension_value="second_dimension_value", timeframe_end=parse_datetime("2022-03-01T05:00:00Z"), timeframe_start=parse_datetime("2022-02-01T05:00:00Z"), view_mode="periodic", @@ -384,7 +609,7 @@ def test_method_fetch_usage_with_all_params(self, client: Orb) -> None: @parametrize def test_raw_response_fetch_usage(self, client: Orb) -> None: response = client.subscriptions.with_raw_response.fetch_usage( - "string", + subscription_id="subscription_id", ) assert response.is_closed is True @@ -396,7 +621,7 @@ def test_raw_response_fetch_usage(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch_usage(self, client: Orb) -> None: with client.subscriptions.with_streaming_response.fetch_usage( - "string", + subscription_id="subscription_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -411,259 +636,182 @@ def test_streaming_response_fetch_usage(self, client: Orb) -> None: def test_path_params_fetch_usage(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.fetch_usage( - "", + subscription_id="", ) @pytest.mark.skip(reason="Incorrect example breaks Prism") @parametrize def test_method_price_intervals(self, client: Orb) -> None: subscription = client.subscriptions.price_intervals( - "string", + subscription_id="subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @pytest.mark.skip(reason="Incorrect example breaks Prism") @parametrize def test_method_price_intervals_with_all_params(self, client: Orb) -> None: subscription = client.subscriptions.price_intervals( - "string", + subscription_id="subscription_id", add=[ { - "price_id": "h74gfhdjvn7ujokd", - "external_price_id": "external_price_id", - "price": { - "external_price_id": "string", - "name": "Annual fee", - "billable_metric_id": "string", - "item_id": "string", - "billed_in_advance": True, - "fixed_price_quantity": 0, - "invoice_grouping_key": "string", - "cadence": "annual", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - "currency": "string", - }, - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "fixed_fee_quantity_transitions": [ - { - "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, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "start_date": "start_of_term", + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", }, - ], + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "can_defer_billing": True, "discounts": [ { - "discount_type": "amount", - "amount_discount": 0, - }, - { - "discount_type": "amount", "amount_discount": 0, - }, - { "discount_type": "amount", - "amount_discount": 0, - }, + } ], - "minimum_amount": 0, - "maximum_amount": 0, - }, - { - "price_id": "h74gfhdjvn7ujokd", + "end_date": "start_of_term", "external_price_id": "external_price_id", - "price": { - "external_price_id": "string", - "name": "Annual fee", - "billable_metric_id": "string", - "item_id": "string", - "billed_in_advance": True, - "fixed_price_quantity": 0, - "invoice_grouping_key": "string", - "cadence": "annual", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - "currency": "string", - }, - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "filter": "my_property > 100 AND my_other_property = 'bar'", "fixed_fee_quantity_transitions": [ { - "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, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - ], - "discounts": [ - { - "discount_type": "amount", - "amount_discount": 0, - }, - { - "discount_type": "amount", - "amount_discount": 0, - }, - { - "discount_type": "amount", - "amount_discount": 0, - }, + } ], - "minimum_amount": 0, "maximum_amount": 0, - }, - { - "price_id": "h74gfhdjvn7ujokd", - "external_price_id": "external_price_id", + "metric_parameter_overrides": {"foo": "bar"}, + "minimum_amount": 0, "price": { - "external_price_id": "string", - "name": "Annual fee", - "billable_metric_id": "string", - "item_id": "string", - "billed_in_advance": True, - "fixed_price_quantity": 0, - "invoice_grouping_key": "string", "cadence": "annual", + "currency": "currency", + "item_id": "item_id", "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - "currency": "string", - }, - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "fixed_fee_quantity_transitions": [ - { - "quantity": 5, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "quantity": 5, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, }, - { - "quantity": 5, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", }, - ], - "discounts": [ - { - "discount_type": "amount", - "amount_discount": 0, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, }, - { - "discount_type": "amount", - "amount_discount": 0, + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", }, - { - "discount_type": "amount", - "amount_discount": 0, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", }, - ], - "minimum_amount": 0, - "maximum_amount": 0, - }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + }, + "price_id": "h74gfhdjvn7ujokd", + "usage_customer_ids": ["string"], + } + ], + add_adjustments=[ + { + "start_date": "start_of_term", + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "adjustment_id": "h74gfhdjvn7ujokd", + "end_date": "start_of_term", + } ], + allow_invoice_credit_or_void=True, + can_defer_billing=True, edit=[ { "price_interval_id": "sdfs6wdjvn7ujokd", - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "fixed_fee_quantity_transitions": [ - { - "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, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - ], "billing_cycle_day": 0, - }, - { - "price_interval_id": "sdfs6wdjvn7ujokd", - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "can_defer_billing": True, + "end_date": "start_of_term", + "filter": "my_property > 100 AND my_other_property = 'bar'", "fixed_fee_quantity_transitions": [ { - "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, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, + } ], - "billing_cycle_day": 0, - }, + "metric_parameter_overrides": {"foo": "bar"}, + "start_date": "start_of_term", + "usage_customer_ids": ["string"], + } + ], + edit_adjustments=[ { - "price_interval_id": "sdfs6wdjvn7ujokd", - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "fixed_fee_quantity_transitions": [ - { - "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, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - ], - "billing_cycle_day": 0, - }, + "adjustment_interval_id": "sdfs6wdjvn7ujokd", + "end_date": "start_of_term", + "start_date": "start_of_term", + } ], ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, 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( - "string", + 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"]) + assert_matches_type(MutatedSubscription, 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( - "string", + 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_matches_type(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -672,108 +820,334 @@ def test_streaming_response_price_intervals(self, client: Orb) -> None: 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_redeem_coupon(self, client: Orb) -> None: + subscription = client.subscriptions.redeem_coupon( + subscription_id="subscription_id", + change_option="requested_date", + ) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) + + @parametrize + def test_method_redeem_coupon_with_all_params(self, client: Orb) -> None: + subscription = client.subscriptions.redeem_coupon( + subscription_id="subscription_id", + change_option="requested_date", + allow_invoice_credit_or_void=True, + change_date=parse_datetime("2017-07-21T17:32:28Z"), + coupon_id="coupon_id", + coupon_redemption_code="coupon_redemption_code", + ) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) + + @parametrize + def test_raw_response_redeem_coupon(self, client: Orb) -> None: + response = client.subscriptions.with_raw_response.redeem_coupon( + subscription_id="subscription_id", + change_option="requested_date", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription = response.parse() + assert_matches_type(MutatedSubscription, subscription, path=["response"]) + + @parametrize + def test_streaming_response_redeem_coupon(self, client: Orb) -> None: + with client.subscriptions.with_streaming_response.redeem_coupon( + subscription_id="subscription_id", + change_option="requested_date", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subscription = response.parse() + assert_matches_type(MutatedSubscription, subscription, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_redeem_coupon(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.redeem_coupon( + subscription_id="", + change_option="requested_date", ) @parametrize def test_method_schedule_plan_change(self, client: Orb) -> None: subscription = client.subscriptions.schedule_plan_change( - "string", + subscription_id="subscription_id", change_option="requested_date", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_method_schedule_plan_change_with_all_params(self, client: Orb) -> None: subscription = client.subscriptions.schedule_plan_change( - "string", + subscription_id="subscription_id", change_option="requested_date", + add_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "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=[ + { + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "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", + "metric_parameter_overrides": {"foo": "bar"}, + "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", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "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, + auto_issuance=True, billing_cycle_alignment="unchanged", - change_date="2017-07-21T17:32:28Z", - coupon_redemption_code="string", + 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", - per_credit_overage_amount="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": "string", - "model_type": "unit", - "minimum_amount": "1.23", - "maximum_amount": "1.23", - "discount": { - "discount_type": "percentage", - "percentage_discount": 0.15, - "trial_amount_discount": "string", - "usage_discount": 0, - "amount_discount": "string", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + "external_price_id": "external_price_id", + "price_id": "h74gfhdjvn7ujokd", + } + ], + replace_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", }, - "fixed_price_quantity": 2, - "unit_config": {"unit_amount": "string"}, - }, + "replaces_adjustment_id": "replaces_adjustment_id", + } + ], + replace_prices=[ { - "id": "string", - "model_type": "unit", - "minimum_amount": "1.23", - "maximum_amount": "1.23", - "discount": { - "discount_type": "percentage", - "percentage_discount": 0.15, - "trial_amount_discount": "string", - "usage_discount": 0, - "amount_discount": "string", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + "replaces_price_id": "replaces_price_id", + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", }, + "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, - "unit_config": {"unit_amount": "string"}, - }, - { - "id": "string", - "model_type": "unit", - "minimum_amount": "1.23", "maximum_amount": "1.23", - "discount": { - "discount_type": "percentage", - "percentage_discount": 0.15, - "trial_amount_discount": "string", - "usage_discount": 0, - "amount_discount": "string", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + "metric_parameter_overrides": {"foo": "bar"}, + "minimum_amount": "1.23", + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", }, - "fixed_price_quantity": 2, - "unit_config": {"unit_amount": "string"}, - }, + "price_id": "h74gfhdjvn7ujokd", + } ], + trial_duration_days=0, + usage_customer_ids=["string"], ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_raw_response_schedule_plan_change(self, client: Orb) -> None: response = client.subscriptions.with_raw_response.schedule_plan_change( - "string", + subscription_id="subscription_id", change_option="requested_date", ) 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(MutatedSubscription, subscription, path=["response"]) @parametrize def test_streaming_response_schedule_plan_change(self, client: Orb) -> None: with client.subscriptions.with_streaming_response.schedule_plan_change( - "string", + subscription_id="subscription_id", change_option="requested_date", ) 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(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -781,46 +1155,47 @@ def test_streaming_response_schedule_plan_change(self, client: Orb) -> None: def test_path_params_schedule_plan_change(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.schedule_plan_change( - "", + subscription_id="", change_option="requested_date", ) @parametrize def test_method_trigger_phase(self, client: Orb) -> None: subscription = client.subscriptions.trigger_phase( - "string", + subscription_id="subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_method_trigger_phase_with_all_params(self, client: Orb) -> None: subscription = client.subscriptions.trigger_phase( - "string", + subscription_id="subscription_id", + allow_invoice_credit_or_void=True, effective_date=parse_date("2019-12-27"), ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_raw_response_trigger_phase(self, client: Orb) -> None: response = client.subscriptions.with_raw_response.trigger_phase( - "string", + 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"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_streaming_response_trigger_phase(self, client: Orb) -> None: with client.subscriptions.with_streaming_response.trigger_phase( - "string", + 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_matches_type(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -828,37 +1203,37 @@ def test_streaming_response_trigger_phase(self, client: Orb) -> None: def test_path_params_trigger_phase(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.trigger_phase( - "", + subscription_id="", ) @parametrize def test_method_unschedule_cancellation(self, client: Orb) -> None: subscription = client.subscriptions.unschedule_cancellation( - "string", + "subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_raw_response_unschedule_cancellation(self, client: Orb) -> None: response = client.subscriptions.with_raw_response.unschedule_cancellation( - "string", + "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"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_streaming_response_unschedule_cancellation(self, client: Orb) -> None: with client.subscriptions.with_streaming_response.unschedule_cancellation( - "string", + "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_matches_type(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -872,34 +1247,34 @@ def test_path_params_unschedule_cancellation(self, client: Orb) -> None: @parametrize def test_method_unschedule_fixed_fee_quantity_updates(self, client: Orb) -> None: subscription = client.subscriptions.unschedule_fixed_fee_quantity_updates( - "string", - price_id="string", + subscription_id="subscription_id", + price_id="price_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_raw_response_unschedule_fixed_fee_quantity_updates(self, client: Orb) -> None: response = client.subscriptions.with_raw_response.unschedule_fixed_fee_quantity_updates( - "string", - price_id="string", + subscription_id="subscription_id", + price_id="price_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"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_streaming_response_unschedule_fixed_fee_quantity_updates(self, client: Orb) -> None: with client.subscriptions.with_streaming_response.unschedule_fixed_fee_quantity_updates( - "string", - price_id="string", + subscription_id="subscription_id", + price_id="price_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_matches_type(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -907,38 +1282,38 @@ def test_streaming_response_unschedule_fixed_fee_quantity_updates(self, client: def test_path_params_unschedule_fixed_fee_quantity_updates(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.unschedule_fixed_fee_quantity_updates( - "", - price_id="string", + subscription_id="", + price_id="price_id", ) @parametrize def test_method_unschedule_pending_plan_changes(self, client: Orb) -> None: subscription = client.subscriptions.unschedule_pending_plan_changes( - "string", + "subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_raw_response_unschedule_pending_plan_changes(self, client: Orb) -> None: response = client.subscriptions.with_raw_response.unschedule_pending_plan_changes( - "string", + "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"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_streaming_response_unschedule_pending_plan_changes(self, client: Orb) -> None: with client.subscriptions.with_streaming_response.unschedule_pending_plan_changes( - "string", + "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_matches_type(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -952,48 +1327,49 @@ def test_path_params_unschedule_pending_plan_changes(self, client: Orb) -> None: @parametrize def test_method_update_fixed_fee_quantity(self, client: Orb) -> None: subscription = client.subscriptions.update_fixed_fee_quantity( - "string", - price_id="string", + subscription_id="subscription_id", + price_id="price_id", quantity=0, ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize def test_method_update_fixed_fee_quantity_with_all_params(self, client: Orb) -> None: subscription = client.subscriptions.update_fixed_fee_quantity( - "string", - price_id="string", + subscription_id="subscription_id", + price_id="price_id", quantity=0, + allow_invoice_credit_or_void=True, change_option="immediate", effective_date=parse_date("2022-12-21"), ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, 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( - "string", - price_id="string", + subscription_id="subscription_id", + 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(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, 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( - "string", - price_id="string", + 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(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1001,94 +1377,318 @@ def test_streaming_response_update_fixed_fee_quantity(self, client: Orb) -> None 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( - "", - price_id="string", + 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(MutatedSubscription, 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(MutatedSubscription, 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(MutatedSubscription, subscription, path=["response"]) + + @parametrize + def test_streaming_response_update_trial(self, client: Orb) -> None: + with 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 = response.parse() + assert_matches_type(MutatedSubscription, subscription, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + 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_trial( + subscription_id="", + trial_end_date=parse_datetime("2017-07-21T17:32:28Z"), + ) + class TestAsyncSubscriptions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @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(MutatedSubscription, 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", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "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=[ + { + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "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", + "metric_parameter_overrides": {"foo": "bar"}, + "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", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "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="string", - coupon_redemption_code="string", + auto_issuance=True, + aws_region="aws_region", + billing_cycle_anchor_configuration={ + "day": 1, + "month": 1, + "year": 0, + }, + coupon_redemption_code="coupon_redemption_code", credits_overage_rate=0, - customer_id="string", - default_invoice_memo="string", + currency="currency", + customer_id="customer_id", + default_invoice_memo="default_invoice_memo", end_date=parse_datetime("2019-12-27T18:11:19.117Z"), - external_customer_id="string", + external_customer_id="external_customer_id", external_marketplace="google", - external_marketplace_reporting_id="string", + external_marketplace_reporting_id="external_marketplace_reporting_id", external_plan_id="ZMwNQefe7J3ecf7W", - initial_phase_order=0, - invoicing_threshold="string", + filter="my_property > 100 AND my_other_property = 'bar'", + initial_phase_order=2, + invoicing_threshold="10.00", metadata={"foo": "string"}, + name="name", net_terms=0, - per_credit_overage_amount="string", + per_credit_overage_amount=0, plan_id="ZMwNQefe7J3ecf7W", - price_overrides=[ + plan_version_number=0, + price_overrides=[{}], + remove_adjustments=[{"adjustment_id": "h74gfhdjvn7ujokd"}], + remove_prices=[ { - "id": "string", - "model_type": "unit", - "minimum_amount": "1.23", - "maximum_amount": "1.23", - "discount": { - "discount_type": "percentage", - "percentage_discount": 0.15, - "trial_amount_discount": "string", - "usage_discount": 0, - "amount_discount": "string", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + "external_price_id": "external_price_id", + "price_id": "h74gfhdjvn7ujokd", + } + ], + replace_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", }, - "fixed_price_quantity": 2, - "unit_config": {"unit_amount": "string"}, - }, + "replaces_adjustment_id": "replaces_adjustment_id", + } + ], + replace_prices=[ { - "id": "string", - "model_type": "unit", - "minimum_amount": "1.23", - "maximum_amount": "1.23", - "discount": { - "discount_type": "percentage", - "percentage_discount": 0.15, - "trial_amount_discount": "string", - "usage_discount": 0, - "amount_discount": "string", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + "replaces_price_id": "replaces_price_id", + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", }, + "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, - "unit_config": {"unit_amount": "string"}, - }, - { - "id": "string", - "model_type": "unit", - "minimum_amount": "1.23", "maximum_amount": "1.23", - "discount": { - "discount_type": "percentage", - "percentage_discount": 0.15, - "trial_amount_discount": "string", - "usage_discount": 0, - "amount_discount": "string", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + "metric_parameter_overrides": {"foo": "bar"}, + "minimum_amount": "1.23", + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", }, - "fixed_price_quantity": 2, - "unit_config": {"unit_amount": "string"}, - }, + "price_id": "h74gfhdjvn7ujokd", + } ], start_date=parse_datetime("2019-12-27T18:11:19.117Z"), + trial_duration_days=0, + usage_customer_ids=["string"], ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncOrb) -> None: @@ -1097,7 +1697,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(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: @@ -1106,42 +1706,95 @@ 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(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - async def test_method_list(self, async_client: AsyncOrb) -> None: - subscription = await async_client.subscriptions.list() - assert_matches_type(AsyncPage[Subscription], subscription, path=["response"]) + async def test_method_update(self, async_client: AsyncOrb) -> None: + subscription = await async_client.subscriptions.update( + subscription_id="subscription_id", + ) + assert_matches_type(Subscription, subscription, path=["response"]) @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: - subscription = await async_client.subscriptions.list( - created_at_gt=parse_datetime("2019-12-27T18:11:19.117Z"), - created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), - created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), - created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), - cursor="string", - customer_id="string", - external_customer_id="string", - limit=0, - status="active", + async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> None: + subscription = await async_client.subscriptions.update( + subscription_id="subscription_id", + auto_collection=True, + auto_issuance=True, + default_invoice_memo="default_invoice_memo", + invoicing_threshold="10.00", + metadata={"foo": "string"}, + net_terms=0, ) - assert_matches_type(AsyncPage[Subscription], subscription, path=["response"]) + assert_matches_type(Subscription, subscription, path=["response"]) @parametrize - async def test_raw_response_list(self, async_client: AsyncOrb) -> None: - response = await async_client.subscriptions.with_raw_response.list() + async def test_raw_response_update(self, async_client: AsyncOrb) -> None: + response = await async_client.subscriptions.with_raw_response.update( + 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(AsyncPage[Subscription], subscription, path=["response"]) + assert_matches_type(Subscription, subscription, path=["response"]) @parametrize - async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: - async with async_client.subscriptions.with_streaming_response.list() as response: + async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: + async with async_client.subscriptions.with_streaming_response.update( + subscription_id="subscription_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subscription = await response.parse() + assert_matches_type(Subscription, subscription, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(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( + subscription_id="", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOrb) -> None: + subscription = await async_client.subscriptions.list() + assert_matches_type(AsyncPage[Subscription], subscription, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: + subscription = await async_client.subscriptions.list( + created_at_gt=parse_datetime("2019-12-27T18:11:19.117Z"), + created_at_gte=parse_datetime("2019-12-27T18:11:19.117Z"), + 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"], + external_customer_id=["string"], + external_plan_id="external_plan_id", + limit=1, + plan_id="plan_id", + status="active", + ) + assert_matches_type(AsyncPage[Subscription], subscription, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOrb) -> None: + response = await async_client.subscriptions.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription = response.parse() + assert_matches_type(AsyncPage[Subscription], subscription, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: + async with async_client.subscriptions.with_streaming_response.list() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1153,43 +1806,44 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_cancel(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.cancel( - "string", + subscription_id="subscription_id", cancel_option="end_of_subscription_term", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_method_cancel_with_all_params(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.cancel( - "string", + subscription_id="subscription_id", cancel_option="end_of_subscription_term", + allow_invoice_credit_or_void=True, cancellation_date=parse_datetime("2019-12-27T18:11:19.117Z"), ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_raw_response_cancel(self, async_client: AsyncOrb) -> None: response = await async_client.subscriptions.with_raw_response.cancel( - "string", + subscription_id="subscription_id", cancel_option="end_of_subscription_term", ) 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(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_streaming_response_cancel(self, async_client: AsyncOrb) -> None: async with async_client.subscriptions.with_streaming_response.cancel( - "string", + subscription_id="subscription_id", cancel_option="end_of_subscription_term", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1197,21 +1851,21 @@ async def test_streaming_response_cancel(self, async_client: AsyncOrb) -> None: async def test_path_params_cancel(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.cancel( - "", + subscription_id="", cancel_option="end_of_subscription_term", ) @parametrize async def test_method_fetch(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.fetch( - "string", + "subscription_id", ) assert_matches_type(Subscription, subscription, path=["response"]) @parametrize async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: response = await async_client.subscriptions.with_raw_response.fetch( - "string", + "subscription_id", ) assert response.is_closed is True @@ -1222,7 +1876,7 @@ async def test_raw_response_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_fetch(self, async_client: AsyncOrb) -> None: async with async_client.subscriptions.with_streaming_response.fetch( - "string", + "subscription_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1242,14 +1896,15 @@ async def test_path_params_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_fetch_costs(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.fetch_costs( - "string", + subscription_id="subscription_id", ) assert_matches_type(SubscriptionFetchCostsResponse, subscription, path=["response"]) @parametrize async def test_method_fetch_costs_with_all_params(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.fetch_costs( - "string", + subscription_id="subscription_id", + currency="currency", timeframe_end=parse_datetime("2022-03-01T05:00:00Z"), timeframe_start=parse_datetime("2022-02-01T05:00:00Z"), view_mode="periodic", @@ -1259,7 +1914,7 @@ async def test_method_fetch_costs_with_all_params(self, async_client: AsyncOrb) @parametrize async def test_raw_response_fetch_costs(self, async_client: AsyncOrb) -> None: response = await async_client.subscriptions.with_raw_response.fetch_costs( - "string", + subscription_id="subscription_id", ) assert response.is_closed is True @@ -1270,7 +1925,7 @@ async def test_raw_response_fetch_costs(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_fetch_costs(self, async_client: AsyncOrb) -> None: async with async_client.subscriptions.with_streaming_response.fetch_costs( - "string", + subscription_id="subscription_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1284,22 +1939,22 @@ async def test_streaming_response_fetch_costs(self, async_client: AsyncOrb) -> N async def test_path_params_fetch_costs(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_costs( - "", + subscription_id="", ) @parametrize async def test_method_fetch_schedule(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.fetch_schedule( - "string", + subscription_id="subscription_id", ) assert_matches_type(AsyncPage[SubscriptionFetchScheduleResponse], subscription, path=["response"]) @parametrize async def test_method_fetch_schedule_with_all_params(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.fetch_schedule( - "string", - cursor="string", - limit=0, + subscription_id="subscription_id", + cursor="cursor", + limit=1, start_date_gt=parse_datetime("2019-12-27T18:11:19.117Z"), start_date_gte=parse_datetime("2019-12-27T18:11:19.117Z"), start_date_lt=parse_datetime("2019-12-27T18:11:19.117Z"), @@ -1310,7 +1965,7 @@ async def test_method_fetch_schedule_with_all_params(self, async_client: AsyncOr @parametrize async def test_raw_response_fetch_schedule(self, async_client: AsyncOrb) -> None: response = await async_client.subscriptions.with_raw_response.fetch_schedule( - "string", + subscription_id="subscription_id", ) assert response.is_closed is True @@ -1321,7 +1976,7 @@ async def test_raw_response_fetch_schedule(self, async_client: AsyncOrb) -> None @parametrize async def test_streaming_response_fetch_schedule(self, async_client: AsyncOrb) -> None: async with async_client.subscriptions.with_streaming_response.fetch_schedule( - "string", + subscription_id="subscription_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1335,14 +1990,14 @@ async def test_streaming_response_fetch_schedule(self, async_client: AsyncOrb) - async def test_path_params_fetch_schedule(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_schedule( - "", + subscription_id="", ) @pytest.mark.skip(reason="Incorrect example breaks Prism") @parametrize async def test_method_fetch_usage(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.fetch_usage( - "string", + subscription_id="subscription_id", ) assert_matches_type(SubscriptionUsage, subscription, path=["response"]) @@ -1350,16 +2005,14 @@ async def test_method_fetch_usage(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_fetch_usage_with_all_params(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.fetch_usage( - "string", - billable_metric_id="string", - cursor="string", - first_dimension_key="string", - first_dimension_value="string", + subscription_id="subscription_id", + billable_metric_id="billable_metric_id", + first_dimension_key="first_dimension_key", + first_dimension_value="first_dimension_value", granularity="day", - group_by="string", - limit=0, - second_dimension_key="string", - second_dimension_value="string", + group_by="group_by", + second_dimension_key="second_dimension_key", + second_dimension_value="second_dimension_value", timeframe_end=parse_datetime("2022-03-01T05:00:00Z"), timeframe_start=parse_datetime("2022-02-01T05:00:00Z"), view_mode="periodic", @@ -1370,7 +2023,7 @@ async def test_method_fetch_usage_with_all_params(self, async_client: AsyncOrb) @parametrize async def test_raw_response_fetch_usage(self, async_client: AsyncOrb) -> None: response = await async_client.subscriptions.with_raw_response.fetch_usage( - "string", + subscription_id="subscription_id", ) assert response.is_closed is True @@ -1382,7 +2035,7 @@ async def test_raw_response_fetch_usage(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_fetch_usage(self, async_client: AsyncOrb) -> None: async with async_client.subscriptions.with_streaming_response.fetch_usage( - "string", + subscription_id="subscription_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1397,259 +2050,182 @@ async def test_streaming_response_fetch_usage(self, async_client: AsyncOrb) -> N 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( - "string", + subscription_id="subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, 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( - "string", + subscription_id="subscription_id", add=[ { - "price_id": "h74gfhdjvn7ujokd", - "external_price_id": "external_price_id", - "price": { - "external_price_id": "string", - "name": "Annual fee", - "billable_metric_id": "string", - "item_id": "string", - "billed_in_advance": True, - "fixed_price_quantity": 0, - "invoice_grouping_key": "string", - "cadence": "annual", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - "currency": "string", - }, - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "fixed_fee_quantity_transitions": [ - { - "quantity": 5, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "quantity": 5, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "start_date": "start_of_term", + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", }, - { - "quantity": 5, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - ], + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "can_defer_billing": True, "discounts": [ { - "discount_type": "amount", - "amount_discount": 0, - }, - { - "discount_type": "amount", "amount_discount": 0, - }, - { "discount_type": "amount", - "amount_discount": 0, - }, + } ], - "minimum_amount": 0, - "maximum_amount": 0, - }, - { - "price_id": "h74gfhdjvn7ujokd", + "end_date": "start_of_term", "external_price_id": "external_price_id", - "price": { - "external_price_id": "string", - "name": "Annual fee", - "billable_metric_id": "string", - "item_id": "string", - "billed_in_advance": True, - "fixed_price_quantity": 0, - "invoice_grouping_key": "string", - "cadence": "annual", - "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - "currency": "string", - }, - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "filter": "my_property > 100 AND my_other_property = 'bar'", "fixed_fee_quantity_transitions": [ { - "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, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, + } ], - "discounts": [ - { - "discount_type": "amount", - "amount_discount": 0, - }, - { - "discount_type": "amount", - "amount_discount": 0, - }, - { - "discount_type": "amount", - "amount_discount": 0, - }, - ], - "minimum_amount": 0, "maximum_amount": 0, - }, - { - "price_id": "h74gfhdjvn7ujokd", - "external_price_id": "external_price_id", + "metric_parameter_overrides": {"foo": "bar"}, + "minimum_amount": 0, "price": { - "external_price_id": "string", - "name": "Annual fee", - "billable_metric_id": "string", - "item_id": "string", - "billed_in_advance": True, - "fixed_price_quantity": 0, - "invoice_grouping_key": "string", "cadence": "annual", + "currency": "currency", + "item_id": "item_id", "model_type": "unit", - "unit_config": {"unit_amount": "string"}, - "currency": "string", - }, - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "fixed_fee_quantity_transitions": [ - { - "quantity": 5, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "quantity": 5, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, }, - { - "quantity": 5, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", }, - ], - "discounts": [ - { - "discount_type": "amount", - "amount_discount": 0, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, }, - { - "discount_type": "amount", - "amount_discount": 0, + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", }, - { - "discount_type": "amount", - "amount_discount": 0, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", }, - ], - "minimum_amount": 0, - "maximum_amount": 0, - }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + }, + "price_id": "h74gfhdjvn7ujokd", + "usage_customer_ids": ["string"], + } + ], + add_adjustments=[ + { + "start_date": "start_of_term", + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "adjustment_id": "h74gfhdjvn7ujokd", + "end_date": "start_of_term", + } ], + allow_invoice_credit_or_void=True, + can_defer_billing=True, edit=[ { "price_interval_id": "sdfs6wdjvn7ujokd", - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "fixed_fee_quantity_transitions": [ - { - "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, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - ], "billing_cycle_day": 0, - }, - { - "price_interval_id": "sdfs6wdjvn7ujokd", - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "can_defer_billing": True, + "end_date": "start_of_term", + "filter": "my_property > 100 AND my_other_property = 'bar'", "fixed_fee_quantity_transitions": [ { - "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, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, + } ], - "billing_cycle_day": 0, - }, + "metric_parameter_overrides": {"foo": "bar"}, + "start_date": "start_of_term", + "usage_customer_ids": ["string"], + } + ], + edit_adjustments=[ { - "price_interval_id": "sdfs6wdjvn7ujokd", - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "fixed_fee_quantity_transitions": [ - { - "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, - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - ], - "billing_cycle_day": 0, - }, + "adjustment_interval_id": "sdfs6wdjvn7ujokd", + "end_date": "start_of_term", + "start_date": "start_of_term", + } ], ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @pytest.mark.skip(reason="Incorrect example breaks Prism") @parametrize async def test_raw_response_price_intervals(self, async_client: AsyncOrb) -> None: response = await async_client.subscriptions.with_raw_response.price_intervals( - "string", + 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"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @pytest.mark.skip(reason="Incorrect example breaks Prism") @parametrize async def test_streaming_response_price_intervals(self, async_client: AsyncOrb) -> None: async with async_client.subscriptions.with_streaming_response.price_intervals( - "string", + subscription_id="subscription_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1658,108 +2234,334 @@ async def test_streaming_response_price_intervals(self, async_client: AsyncOrb) async def test_path_params_price_intervals(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.price_intervals( - "", + subscription_id="", + ) + + @parametrize + async def test_method_redeem_coupon(self, async_client: AsyncOrb) -> None: + subscription = await async_client.subscriptions.redeem_coupon( + subscription_id="subscription_id", + change_option="requested_date", + ) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) + + @parametrize + async def test_method_redeem_coupon_with_all_params(self, async_client: AsyncOrb) -> None: + subscription = await async_client.subscriptions.redeem_coupon( + subscription_id="subscription_id", + change_option="requested_date", + allow_invoice_credit_or_void=True, + change_date=parse_datetime("2017-07-21T17:32:28Z"), + coupon_id="coupon_id", + coupon_redemption_code="coupon_redemption_code", + ) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) + + @parametrize + async def test_raw_response_redeem_coupon(self, async_client: AsyncOrb) -> None: + response = await async_client.subscriptions.with_raw_response.redeem_coupon( + subscription_id="subscription_id", + change_option="requested_date", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription = response.parse() + assert_matches_type(MutatedSubscription, subscription, path=["response"]) + + @parametrize + async def test_streaming_response_redeem_coupon(self, async_client: AsyncOrb) -> None: + async with async_client.subscriptions.with_streaming_response.redeem_coupon( + subscription_id="subscription_id", + change_option="requested_date", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subscription = await response.parse() + assert_matches_type(MutatedSubscription, subscription, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_redeem_coupon(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.redeem_coupon( + subscription_id="", + change_option="requested_date", ) @parametrize async def test_method_schedule_plan_change(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.schedule_plan_change( - "string", + subscription_id="subscription_id", change_option="requested_date", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, 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( - "string", + subscription_id="subscription_id", change_option="requested_date", + add_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", + }, + "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=[ + { + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", + }, + "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", + "metric_parameter_overrides": {"foo": "bar"}, + "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", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "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, + auto_issuance=True, billing_cycle_alignment="unchanged", - change_date="2017-07-21T17:32:28Z", - coupon_redemption_code="string", + 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", - per_credit_overage_amount="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": "string", - "model_type": "unit", - "minimum_amount": "1.23", - "maximum_amount": "1.23", - "discount": { - "discount_type": "percentage", - "percentage_discount": 0.15, - "trial_amount_discount": "string", - "usage_discount": 0, - "amount_discount": "string", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + "external_price_id": "external_price_id", + "price_id": "h74gfhdjvn7ujokd", + } + ], + replace_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "percentage_discount": 0, + "applies_to_all": True, + "applies_to_item_ids": ["item_1", "item_2"], + "applies_to_price_ids": ["price_1", "price_2"], + "currency": "currency", + "filters": [ + { + "field": "price_id", + "operator": "includes", + "values": ["string"], + } + ], + "is_invoice_level": True, + "price_type": "usage", }, - "fixed_price_quantity": 2, - "unit_config": {"unit_amount": "string"}, - }, + "replaces_adjustment_id": "replaces_adjustment_id", + } + ], + replace_prices=[ { - "id": "string", - "model_type": "unit", - "minimum_amount": "1.23", - "maximum_amount": "1.23", - "discount": { - "discount_type": "percentage", - "percentage_discount": 0.15, - "trial_amount_discount": "string", - "usage_discount": 0, - "amount_discount": "string", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + "replaces_price_id": "replaces_price_id", + "allocation_price": { + "amount": "10.00", + "cadence": "monthly", + "currency": "USD", + "custom_expiration": { + "duration": 0, + "duration_unit": "day", + }, + "expires_at_end_of_cadence": True, + "filters": [ + { + "field": "item_id", + "operator": "includes", + "values": ["string"], + } + ], + "item_id": "item_id", + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "per_unit_cost_basis": "per_unit_cost_basis", }, + "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, - "unit_config": {"unit_amount": "string"}, - }, - { - "id": "string", - "model_type": "unit", - "minimum_amount": "1.23", "maximum_amount": "1.23", - "discount": { - "discount_type": "percentage", - "percentage_discount": 0.15, - "trial_amount_discount": "string", - "usage_discount": 0, - "amount_discount": "string", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + "metric_parameter_overrides": {"foo": "bar"}, + "minimum_amount": "1.23", + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": { + "unit_amount": "unit_amount", + "prorated": True, + }, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "conversion_rate_config": { + "conversion_rate_type": "unit", + "unit_config": {"unit_amount": "unit_amount"}, + }, + "currency": "currency", + "dimensional_price_configuration": { + "dimension_values": ["string"], + "dimensional_price_group_id": "dimensional_price_group_id", + "external_dimensional_price_group_id": "external_dimensional_price_group_id", + }, + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "x", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "license_type_id": "license_type_id", + "metadata": {"foo": "string"}, + "reference_id": "reference_id", }, - "fixed_price_quantity": 2, - "unit_config": {"unit_amount": "string"}, - }, + "price_id": "h74gfhdjvn7ujokd", + } ], + trial_duration_days=0, + usage_customer_ids=["string"], ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_raw_response_schedule_plan_change(self, async_client: AsyncOrb) -> None: response = await async_client.subscriptions.with_raw_response.schedule_plan_change( - "string", + subscription_id="subscription_id", change_option="requested_date", ) 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(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_streaming_response_schedule_plan_change(self, async_client: AsyncOrb) -> None: async with async_client.subscriptions.with_streaming_response.schedule_plan_change( - "string", + subscription_id="subscription_id", change_option="requested_date", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1767,46 +2569,47 @@ async def test_streaming_response_schedule_plan_change(self, async_client: Async async def test_path_params_schedule_plan_change(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.schedule_plan_change( - "", + subscription_id="", change_option="requested_date", ) @parametrize async def test_method_trigger_phase(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.trigger_phase( - "string", + subscription_id="subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_method_trigger_phase_with_all_params(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.trigger_phase( - "string", + subscription_id="subscription_id", + allow_invoice_credit_or_void=True, effective_date=parse_date("2019-12-27"), ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_raw_response_trigger_phase(self, async_client: AsyncOrb) -> None: response = await async_client.subscriptions.with_raw_response.trigger_phase( - "string", + 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"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_streaming_response_trigger_phase(self, async_client: AsyncOrb) -> None: async with async_client.subscriptions.with_streaming_response.trigger_phase( - "string", + subscription_id="subscription_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1814,37 +2617,37 @@ async def test_streaming_response_trigger_phase(self, async_client: AsyncOrb) -> async def test_path_params_trigger_phase(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.trigger_phase( - "", + subscription_id="", ) @parametrize async def test_method_unschedule_cancellation(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.unschedule_cancellation( - "string", + "subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_raw_response_unschedule_cancellation(self, async_client: AsyncOrb) -> None: response = await async_client.subscriptions.with_raw_response.unschedule_cancellation( - "string", + "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"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_streaming_response_unschedule_cancellation(self, async_client: AsyncOrb) -> None: async with async_client.subscriptions.with_streaming_response.unschedule_cancellation( - "string", + "subscription_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1858,34 +2661,34 @@ async def test_path_params_unschedule_cancellation(self, async_client: AsyncOrb) @parametrize async def test_method_unschedule_fixed_fee_quantity_updates(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.unschedule_fixed_fee_quantity_updates( - "string", - price_id="string", + subscription_id="subscription_id", + price_id="price_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_raw_response_unschedule_fixed_fee_quantity_updates(self, async_client: AsyncOrb) -> None: response = await async_client.subscriptions.with_raw_response.unschedule_fixed_fee_quantity_updates( - "string", - price_id="string", + subscription_id="subscription_id", + price_id="price_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"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_streaming_response_unschedule_fixed_fee_quantity_updates(self, async_client: AsyncOrb) -> None: async with async_client.subscriptions.with_streaming_response.unschedule_fixed_fee_quantity_updates( - "string", - price_id="string", + subscription_id="subscription_id", + price_id="price_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1893,38 +2696,38 @@ async def test_streaming_response_unschedule_fixed_fee_quantity_updates(self, as async def test_path_params_unschedule_fixed_fee_quantity_updates(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.unschedule_fixed_fee_quantity_updates( - "", - price_id="string", + subscription_id="", + price_id="price_id", ) @parametrize async def test_method_unschedule_pending_plan_changes(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.unschedule_pending_plan_changes( - "string", + "subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_raw_response_unschedule_pending_plan_changes(self, async_client: AsyncOrb) -> None: response = await async_client.subscriptions.with_raw_response.unschedule_pending_plan_changes( - "string", + "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"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_streaming_response_unschedule_pending_plan_changes(self, async_client: AsyncOrb) -> None: async with async_client.subscriptions.with_streaming_response.unschedule_pending_plan_changes( - "string", + "subscription_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1938,48 +2741,49 @@ async def test_path_params_unschedule_pending_plan_changes(self, async_client: A @parametrize async def test_method_update_fixed_fee_quantity(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.update_fixed_fee_quantity( - "string", - price_id="string", + subscription_id="subscription_id", + price_id="price_id", quantity=0, ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_method_update_fixed_fee_quantity_with_all_params(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.update_fixed_fee_quantity( - "string", - price_id="string", + subscription_id="subscription_id", + price_id="price_id", quantity=0, + allow_invoice_credit_or_void=True, change_option="immediate", effective_date=parse_date("2022-12-21"), ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_raw_response_update_fixed_fee_quantity(self, async_client: AsyncOrb) -> None: response = await async_client.subscriptions.with_raw_response.update_fixed_fee_quantity( - "string", - price_id="string", + subscription_id="subscription_id", + 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(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) @parametrize async def test_streaming_response_update_fixed_fee_quantity(self, async_client: AsyncOrb) -> None: async with async_client.subscriptions.with_streaming_response.update_fixed_fee_quantity( - "string", - price_id="string", + 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 = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(MutatedSubscription, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1987,7 +2791,58 @@ async def test_streaming_response_update_fixed_fee_quantity(self, async_client: async def test_path_params_update_fixed_fee_quantity(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_fixed_fee_quantity( - "", - price_id="string", + subscription_id="", + 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(MutatedSubscription, 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(MutatedSubscription, 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(MutatedSubscription, 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(MutatedSubscription, 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/api_resources/test_top_level.py b/tests/api_resources/test_top_level.py index 6971f1e7..217fbeef 100644 --- a/tests/api_resources/test_top_level.py +++ b/tests/api_resources/test_top_level.py @@ -44,7 +44,9 @@ def test_streaming_response_ping(self, client: Orb) -> None: class TestAsyncTopLevel: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_ping(self, async_client: AsyncOrb) -> None: diff --git a/tests/conftest.py b/tests/conftest.py index a718a9e3..1d22f0ef 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,27 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + from __future__ import annotations import os -import asyncio import logging from typing import TYPE_CHECKING, Iterator, AsyncIterator +import httpx import pytest +from pytest_asyncio import is_async_test -from orb import Orb, AsyncOrb +from orb import Orb, AsyncOrb, DefaultAioHttpClient +from orb._utils import is_dict if TYPE_CHECKING: - from _pytest.fixtures import FixtureRequest + from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage] pytest.register_assert_rewrite("tests.utils") 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) + + # We skip tests that use both the aiohttp client and respx_mock as respx_mock + # doesn't support custom transports. + for item in items: + if "async_client" not in item.fixturenames or "respx_mock" not in item.fixturenames: + continue + + if not hasattr(item, "callspec"): + continue + + async_client_param = item.callspec.params.get("async_client") + if is_dict(async_client_param) and async_client_param.get("http_client") == "aiohttp": + item.add_marker(pytest.mark.skip(reason="aiohttp client is not compatible with respx_mock")) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -41,9 +60,25 @@ def client(request: FixtureRequest) -> Iterator[Orb]: @pytest.fixture(scope="session") async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncOrb]: - strict = getattr(request, "param", True) - if not isinstance(strict, bool): - raise TypeError(f"Unexpected fixture parameter type {type(strict)}, expected {bool}") - - async with AsyncOrb(base_url=base_url, api_key=api_key, _strict_response_validation=strict) as client: + param = getattr(request, "param", True) + + # defaults + strict = True + http_client: None | httpx.AsyncClient = None + + if isinstance(param, bool): + strict = param + elif is_dict(param): + strict = param.get("strict", True) + assert isinstance(strict, bool) + + http_client_type = param.get("http_client", "httpx") + if http_client_type == "aiohttp": + http_client = DefaultAioHttpClient() + else: + raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict") + + async with AsyncOrb( + base_url=base_url, api_key=api_key, _strict_response_validation=strict, http_client=http_client + ) as client: yield client diff --git a/tests/test_client.py b/tests/test_client.py index 510492e2..d6290454 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -4,12 +4,15 @@ import gc import os +import sys import json import asyncio import inspect +import dataclasses import tracemalloc -from typing import Any, Union, cast +from typing import Any, Union, TypeVar, Callable, Iterable, Iterator, Optional, Coroutine, cast from unittest import mock +from typing_extensions import Literal, AsyncIterator, override import httpx import pytest @@ -17,14 +20,24 @@ from pydantic import ValidationError from orb import Orb, AsyncOrb, APIResponseValidationError -from orb._client import Orb, AsyncOrb +from orb._types import Omit +from orb._utils import asyncify from orb._models import BaseModel, FinalRequestOptions -from orb._constants import RAW_RESPONSE_HEADER from orb._exceptions import OrbError, APIStatusError, APITimeoutError, APIResponseValidationError -from orb._base_client import DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, BaseClient, make_request_options +from orb._base_client import ( + DEFAULT_TIMEOUT, + HTTPX_DEFAULT_TIMEOUT, + BaseClient, + OtherPlatform, + DefaultHttpxClient, + DefaultAsyncHttpxClient, + get_platform, + make_request_options, +) from .utils import update_env +T = TypeVar("T") base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") api_key = "My API Key" @@ -39,6 +52,57 @@ def _low_retry_timeout(*_args: Any, **_kwargs: Any) -> float: return 0.1 +def mirror_request_content(request: httpx.Request) -> httpx.Response: + return httpx.Response(200, content=request.content) + + +# note: we can't use the httpx.MockTransport class as it consumes the request +# body itself, which means we can't test that the body is read lazily +class MockTransport(httpx.BaseTransport, httpx.AsyncBaseTransport): + def __init__( + self, + handler: Callable[[httpx.Request], httpx.Response] + | Callable[[httpx.Request], Coroutine[Any, Any, httpx.Response]], + ) -> None: + self.handler = handler + + @override + def handle_request( + self, + request: httpx.Request, + ) -> httpx.Response: + assert not inspect.iscoroutinefunction(self.handler), "handler must not be a coroutine function" + assert inspect.isfunction(self.handler), "handler must be a function" + return self.handler(request) + + @override + async def handle_async_request( + self, + request: httpx.Request, + ) -> httpx.Response: + assert inspect.iscoroutinefunction(self.handler), "handler must be a coroutine function" + return await self.handler(request) + + +@dataclasses.dataclass +class Counter: + value: int = 0 + + +def _make_sync_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> Iterator[T]: + for item in iterable: + if counter: + counter.value += 1 + yield item + + +async def _make_async_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> AsyncIterator[T]: + for item in iterable: + if counter: + counter.value += 1 + yield item + + def _get_open_connections(client: Orb | AsyncOrb) -> int: transport = client._client._transport assert isinstance(transport, httpx.HTTPTransport) or isinstance(transport, httpx.AsyncHTTPTransport) @@ -48,51 +112,49 @@ def _get_open_connections(client: Orb | AsyncOrb) -> int: class TestOrb: - client = Orb(base_url=base_url, api_key=api_key, _strict_response_validation=True) - @pytest.mark.respx(base_url=base_url) - def test_raw_response(self, respx_mock: MockRouter) -> None: + def test_raw_response(self, respx_mock: MockRouter, client: Orb) -> None: respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.post("/foo", cast_to=httpx.Response) + response = client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} @pytest.mark.respx(base_url=base_url) - def test_raw_response_for_binary(self, respx_mock: MockRouter) -> None: + def test_raw_response_for_binary(self, respx_mock: MockRouter, client: Orb) -> None: respx_mock.post("/foo").mock( return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') ) - response = self.client.post("/foo", cast_to=httpx.Response) + response = client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} - def test_copy(self) -> None: - copied = self.client.copy() - assert id(copied) != id(self.client) + def test_copy(self, client: Orb) -> None: + copied = client.copy() + assert id(copied) != id(client) - copied = self.client.copy(api_key="another My API Key") + copied = client.copy(api_key="another My API Key") assert copied.api_key == "another My API Key" - assert self.client.api_key == "My API Key" + assert client.api_key == "My API Key" - def test_copy_default_options(self) -> None: + def test_copy_default_options(self, client: Orb) -> None: # options that have a default are overridden correctly - copied = self.client.copy(max_retries=7) + copied = client.copy(max_retries=7) assert copied.max_retries == 7 - assert self.client.max_retries == 2 + assert client.max_retries == 2 copied2 = copied.copy(max_retries=6) assert copied2.max_retries == 6 assert copied.max_retries == 7 # timeout - assert isinstance(self.client.timeout, httpx.Timeout) - copied = self.client.copy(timeout=None) + assert isinstance(client.timeout, httpx.Timeout) + copied = client.copy(timeout=None) assert copied.timeout is None - assert isinstance(self.client.timeout, httpx.Timeout) + assert isinstance(client.timeout, httpx.Timeout) def test_copy_default_headers(self) -> None: client = Orb( @@ -127,6 +189,7 @@ def test_copy_default_headers(self) -> None: match="`default_headers` and `set_default_headers` arguments are mutually exclusive", ): client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) + client.close() def test_copy_default_query(self) -> None: client = Orb(base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"foo": "bar"}) @@ -162,13 +225,15 @@ def test_copy_default_query(self) -> None: ): client.copy(set_default_query={}, default_query={"foo": "Bar"}) - def test_copy_signature(self) -> None: + client.close() + + def test_copy_signature(self, client: Orb) -> None: # ensure the same parameters that can be passed to the client are defined in the `.copy()` method init_signature = inspect.signature( # mypy doesn't like that we access the `__init__` property. - self.client.__init__, # type: ignore[misc] + client.__init__, # type: ignore[misc] ) - copy_signature = inspect.signature(self.client.copy) + copy_signature = inspect.signature(client.copy) exclude_params = {"transport", "proxies", "_strict_response_validation"} for name in init_signature.parameters.keys(): @@ -178,12 +243,13 @@ def test_copy_signature(self) -> None: copy_param = copy_signature.parameters.get(name) assert copy_param is not None, f"copy() signature is missing the {name} param" - def test_copy_build_request(self) -> None: + @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") + def test_copy_build_request(self, client: Orb) -> None: options = FinalRequestOptions(method="get", url="/foo") def build_request(options: FinalRequestOptions) -> None: - client = self.client.copy() - client._build_request(options) + client_copy = client.copy() + client_copy._build_request(options) # ensure that the machinery is warmed up before tracing starts. build_request(options) @@ -240,14 +306,12 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic print(frame) raise AssertionError() - def test_request_timeout(self) -> None: - request = self.client._build_request(FinalRequestOptions(method="get", url="/foo")) + def test_request_timeout(self, client: Orb) -> None: + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT - request = self.client._build_request( - FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)) - ) + request = client._build_request(FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0))) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(100.0) @@ -258,6 +322,8 @@ def test_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(0) + client.close() + def test_http_client_timeout_option(self) -> None: # custom timeout given to the httpx client should be used with httpx.Client(timeout=None) as http_client: @@ -267,6 +333,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(None) + client.close() + # no timeout given to the httpx client should not use the httpx default with httpx.Client() as http_client: client = Orb(base_url=base_url, api_key=api_key, _strict_response_validation=True, http_client=http_client) @@ -275,6 +343,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT + client.close() + # explicitly passing the default timeout currently results in it being ignored with httpx.Client(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: client = Orb(base_url=base_url, api_key=api_key, _strict_response_validation=True, http_client=http_client) @@ -283,6 +353,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT # our default + client.close() + async def test_invalid_http_client(self) -> None: with pytest.raises(TypeError, match="Invalid `http_client` arg"): async with httpx.AsyncClient() as http_client: @@ -294,14 +366,14 @@ async def test_invalid_http_client(self) -> None: ) def test_default_headers_option(self) -> None: - client = Orb( + test_client = Orb( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} ) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "bar" assert request.headers.get("x-stainless-lang") == "python" - client2 = Orb( + test_client2 = Orb( base_url=base_url, api_key=api_key, _strict_response_validation=True, @@ -310,17 +382,21 @@ def test_default_headers_option(self) -> None: "X-Stainless-Lang": "my-overriding-header", }, ) - request = client2._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "stainless" assert request.headers.get("x-stainless-lang") == "my-overriding-header" + test_client.close() + test_client2.close() + def test_validate_headers(self) -> None: client = Orb(base_url=base_url, api_key=api_key, _strict_response_validation=True) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("Authorization") == f"Bearer {api_key}" with pytest.raises(OrbError): - client2 = Orb(base_url=base_url, api_key=None, _strict_response_validation=True) + with update_env(**{"ORB_API_KEY": Omit()}): + client2 = Orb(base_url=base_url, api_key=None, _strict_response_validation=True) _ = client2 def test_default_query_option(self) -> None: @@ -335,14 +411,40 @@ def test_default_query_option(self) -> None: FinalRequestOptions( method="get", url="/foo", - params={"foo": "baz", "query_param": "overriden"}, + params={"foo": "baz", "query_param": "overridden"}, ) ) url = httpx.URL(request.url) - assert dict(url.params) == {"foo": "baz", "query_param": "overriden"} + assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} - def test_request_extra_json(self) -> None: - request = self.client._build_request( + client.close() + + def test_hardcoded_query_params_in_url(self, client: Orb) -> None: + request = client._build_request(FinalRequestOptions(method="get", url="/foo?beta=true")) + url = httpx.URL(request.url) + assert dict(url.params) == {"beta": "true"} + + request = client._build_request( + FinalRequestOptions( + method="get", + url="/foo?beta=true", + params={"limit": "10", "page": "abc"}, + ) + ) + url = httpx.URL(request.url) + assert dict(url.params) == {"beta": "true", "limit": "10", "page": "abc"} + + request = client._build_request( + FinalRequestOptions( + method="get", + url="/files/a%2Fb?beta=true", + params={"limit": "10"}, + ) + ) + assert request.url.raw_path == b"/files/a%2Fb?beta=true&limit=10" + + def test_request_extra_json(self, client: Orb) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -353,7 +455,7 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": False} - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -364,7 +466,7 @@ def test_request_extra_json(self) -> None: assert data == {"baz": False} # `extra_json` takes priority over `json_data` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -375,8 +477,8 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": None} - def test_request_extra_headers(self) -> None: - request = self.client._build_request( + def test_request_extra_headers(self, client: Orb) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -386,7 +488,7 @@ def test_request_extra_headers(self) -> None: assert request.headers.get("X-Foo") == "Foo" # `extra_headers` takes priority over `default_headers` when keys clash - request = self.client.with_options(default_headers={"X-Bar": "true"})._build_request( + request = client.with_options(default_headers={"X-Bar": "true"})._build_request( FinalRequestOptions( method="post", url="/foo", @@ -397,8 +499,8 @@ def test_request_extra_headers(self) -> None: ) assert request.headers.get("X-Bar") == "false" - def test_request_extra_query(self) -> None: - request = self.client._build_request( + def test_request_extra_query(self, client: Orb) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -411,7 +513,7 @@ def test_request_extra_query(self) -> None: assert params == {"my_query_param": "Foo"} # if both `query` and `extra_query` are given, they are merged - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -425,7 +527,7 @@ def test_request_extra_query(self) -> None: assert params == {"bar": "1", "foo": "2"} # `extra_query` takes priority over `query` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -441,7 +543,7 @@ def test_request_extra_query(self) -> None: def test_multipart_repeating_array(self, client: Orb) -> None: request = client._build_request( FinalRequestOptions.construct( - method="get", + method="post", url="/foo", headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, json_data={"array": ["foo", "bar"]}, @@ -468,7 +570,71 @@ def test_multipart_repeating_array(self, client: Orb) -> None: ] @pytest.mark.respx(base_url=base_url) - def test_basic_union_response(self, respx_mock: MockRouter) -> None: + def test_binary_content_upload(self, respx_mock: MockRouter, client: Orb) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + response = client.post( + "/upload", + content=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + + def test_binary_content_upload_with_iterator(self) -> None: + file_content = b"Hello, this is a test file." + counter = Counter() + iterator = _make_sync_iterator([file_content], counter=counter) + + def mock_handler(request: httpx.Request) -> httpx.Response: + assert counter.value == 0, "the request body should not have been read" + return httpx.Response(200, content=request.read()) + + with Orb( + base_url=base_url, + api_key=api_key, + _strict_response_validation=True, + http_client=httpx.Client(transport=MockTransport(handler=mock_handler)), + ) as client: + response = client.post( + "/upload", + content=iterator, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + assert counter.value == 1 + + @pytest.mark.respx(base_url=base_url) + def test_binary_content_upload_with_body_is_deprecated(self, respx_mock: MockRouter, client: Orb) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + with pytest.deprecated_call( + match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead." + ): + response = client.post( + "/upload", + body=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + + @pytest.mark.respx(base_url=base_url) + def test_basic_union_response(self, respx_mock: MockRouter, client: Orb) -> None: class Model1(BaseModel): name: str @@ -477,12 +643,12 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" @pytest.mark.respx(base_url=base_url) - def test_union_response_different_types(self, respx_mock: MockRouter) -> None: + def test_union_response_different_types(self, respx_mock: MockRouter, client: Orb) -> None: """Union of objects with the same field name using a different type""" class Model1(BaseModel): @@ -493,18 +659,18 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model1) assert response.foo == 1 @pytest.mark.respx(base_url=base_url) - def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter) -> None: + def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter, client: Orb) -> None: """ Response that sets Content-Type to something other than application/json but returns json data """ @@ -520,29 +686,29 @@ class Model(BaseModel): ) ) - response = self.client.get("/foo", cast_to=Model) + response = client.get("/foo", cast_to=Model) assert isinstance(response, Model) assert response.foo == 2 @pytest.mark.respx(base_url=base_url) - def test_idempotency_header_options(self, respx_mock: MockRouter) -> None: + def test_idempotency_header_options(self, respx_mock: MockRouter, client: Orb) -> None: respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={})) - response = self.client.post("/foo", cast_to=httpx.Response) + response = client.post("/foo", cast_to=httpx.Response) header = response.request.headers.get("Idempotency-Key") assert header is not None assert header.startswith("stainless-python-retry") # explicit header - response = self.client.post( + response = client.post( "/foo", cast_to=httpx.Response, options=make_request_options(extra_headers={"Idempotency-Key": "custom-key"}), ) assert response.request.headers.get("Idempotency-Key") == "custom-key" - response = self.client.post( + response = client.post( "/foo", cast_to=httpx.Response, options=make_request_options(extra_headers={"idempotency-key": "custom-key"}), @@ -550,7 +716,7 @@ def test_idempotency_header_options(self, respx_mock: MockRouter) -> None: assert response.request.headers.get("Idempotency-Key") == "custom-key" # custom argument - response = self.client.post( + response = client.post( "/foo", cast_to=httpx.Response, options=make_request_options(idempotency_key="custom-key") ) assert response.request.headers.get("Idempotency-Key") == "custom-key" @@ -563,6 +729,8 @@ def test_base_url_setter(self) -> None: assert client.base_url == "https://example.com/from_setter/" + client.close() + def test_base_url_env(self) -> None: with update_env(ORB_BASE_URL="http://localhost:5000/from/env"): client = Orb(api_key=api_key, _strict_response_validation=True) @@ -590,6 +758,7 @@ def test_base_url_trailing_slash(self, client: Orb) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + client.close() @pytest.mark.parametrize( "client", @@ -613,6 +782,7 @@ def test_base_url_no_trailing_slash(self, client: Orb) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + client.close() @pytest.mark.parametrize( "client", @@ -636,38 +806,43 @@ def test_absolute_request_url(self, client: Orb) -> None: ), ) assert request.url == "https://myapi.com/foo" + client.close() def test_copied_client_does_not_close_http(self) -> None: - client = Orb(base_url=base_url, api_key=api_key, _strict_response_validation=True) - assert not client.is_closed() + test_client = Orb(base_url=base_url, api_key=api_key, _strict_response_validation=True) + assert not test_client.is_closed() - copied = client.copy() - assert copied is not client + copied = test_client.copy() + assert copied is not test_client del copied - assert not client.is_closed() + assert not test_client.is_closed() def test_client_context_manager(self) -> None: - client = Orb(base_url=base_url, api_key=api_key, _strict_response_validation=True) - with client as c2: - assert c2 is client + test_client = Orb(base_url=base_url, api_key=api_key, _strict_response_validation=True) + with test_client as c2: + assert c2 is test_client assert not c2.is_closed() - assert not client.is_closed() - assert client.is_closed() + assert not test_client.is_closed() + assert test_client.is_closed() @pytest.mark.respx(base_url=base_url) - def test_client_response_validation_error(self, respx_mock: MockRouter) -> None: + def test_client_response_validation_error(self, respx_mock: MockRouter, client: Orb) -> None: class Model(BaseModel): foo: str respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) with pytest.raises(APIResponseValidationError) as exc: - self.client.get("/foo", cast_to=Model) + client.get("/foo", cast_to=Model) assert isinstance(exc.value.__cause__, ValidationError) + def test_client_max_retries_validation(self) -> None: + with pytest.raises(TypeError, match=r"max_retries cannot be None"): + Orb(base_url=base_url, api_key=api_key, _strict_response_validation=True, max_retries=cast(Any, None)) + @pytest.mark.respx(base_url=base_url) def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None: class Model(BaseModel): @@ -680,11 +855,14 @@ class Model(BaseModel): with pytest.raises(APIResponseValidationError): strict_client.get("/foo", cast_to=Model) - client = Orb(base_url=base_url, api_key=api_key, _strict_response_validation=False) + non_strict_client = Orb(base_url=base_url, api_key=api_key, _strict_response_validation=False) - response = client.get("/foo", cast_to=Model) + response = non_strict_client.get("/foo", cast_to=Model) assert isinstance(response, str) # type: ignore[unreachable] + strict_client.close() + non_strict_client.close() + @pytest.mark.parametrize( "remaining_retries,retry_after,timeout", [ @@ -703,12 +881,13 @@ 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)) - def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str, timeout: float) -> None: - client = Orb(base_url=base_url, api_key=api_key, _strict_response_validation=True) - + def test_parse_retry_after_header( + self, remaining_retries: int, retry_after: str, timeout: float, client: Orb + ) -> None: headers = httpx.Headers({"retry-after": retry_after}) options = FinalRequestOptions(method="get", url="/foo", max_retries=3) calculated = client._calculate_retry_timeout(remaining_retries, options, headers) @@ -716,85 +895,227 @@ def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str @mock.patch("orb._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: Orb) -> None: respx_mock.post("/customers").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - self.client.post( - "/customers", - body=cast(object, dict(email="example-customer@withorb.com", name="My Customer")), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) + client.customers.with_streaming_response.create(email="dev@stainless.com", name="x").__enter__() - assert _get_open_connections(self.client) == 0 + assert _get_open_connections(client) == 0 @mock.patch("orb._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: Orb) -> None: respx_mock.post("/customers").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - self.client.post( - "/customers", - body=cast(object, dict(email="example-customer@withorb.com", name="My Customer")), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) + client.customers.with_streaming_response.create(email="dev@stainless.com", name="x").__enter__() + assert _get_open_connections(client) == 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.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 + + 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="dev@stainless.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) - assert _get_open_connections(self.client) == 0 + 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) -class TestAsyncOrb: - client = AsyncOrb(base_url=base_url, api_key=api_key, _strict_response_validation=True) + respx_mock.post("/customers").mock(side_effect=retry_handler) + response = client.customers.with_raw_response.create( + email="dev@stainless.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_raw_response(self, respx_mock: MockRouter) -> None: + 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@stainless.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) + @pytest.mark.respx(base_url=base_url) + def test_retries_taken_new_response_class( + 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) + + with client.customers.with_streaming_response.create(email="dev@stainless.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_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: + # Test that the proxy environment variables are set correctly + monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + # Delete in case our environment has any proxy env vars set + monkeypatch.delenv("HTTP_PROXY", raising=False) + monkeypatch.delenv("ALL_PROXY", raising=False) + monkeypatch.delenv("NO_PROXY", raising=False) + monkeypatch.delenv("http_proxy", raising=False) + monkeypatch.delenv("https_proxy", raising=False) + monkeypatch.delenv("all_proxy", raising=False) + monkeypatch.delenv("no_proxy", raising=False) + + client = DefaultHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + + @pytest.mark.respx(base_url=base_url) + def test_follow_redirects(self, respx_mock: MockRouter, client: Orb) -> None: + # Test that the default follow_redirects=True allows following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) + + response = client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + assert response.status_code == 200 + assert response.json() == {"status": "ok"} + + @pytest.mark.respx(base_url=base_url) + def test_follow_redirects_disabled(self, respx_mock: MockRouter, client: Orb) -> None: + # Test that follow_redirects=False prevents following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + + with pytest.raises(APIStatusError) as exc_info: + client.post("/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response) + + assert exc_info.value.response.status_code == 302 + assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" + + +class TestAsyncOrb: + @pytest.mark.respx(base_url=base_url) + async def test_raw_response(self, respx_mock: MockRouter, async_client: AsyncOrb) -> None: respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.post("/foo", cast_to=httpx.Response) + response = await async_client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_raw_response_for_binary(self, respx_mock: MockRouter) -> None: + async def test_raw_response_for_binary(self, respx_mock: MockRouter, async_client: AsyncOrb) -> None: respx_mock.post("/foo").mock( return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') ) - response = await self.client.post("/foo", cast_to=httpx.Response) + response = await async_client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} - def test_copy(self) -> None: - copied = self.client.copy() - assert id(copied) != id(self.client) + def test_copy(self, async_client: AsyncOrb) -> None: + copied = async_client.copy() + assert id(copied) != id(async_client) - copied = self.client.copy(api_key="another My API Key") + copied = async_client.copy(api_key="another My API Key") assert copied.api_key == "another My API Key" - assert self.client.api_key == "My API Key" + assert async_client.api_key == "My API Key" - def test_copy_default_options(self) -> None: + def test_copy_default_options(self, async_client: AsyncOrb) -> None: # options that have a default are overridden correctly - copied = self.client.copy(max_retries=7) + copied = async_client.copy(max_retries=7) assert copied.max_retries == 7 - assert self.client.max_retries == 2 + assert async_client.max_retries == 2 copied2 = copied.copy(max_retries=6) assert copied2.max_retries == 6 assert copied.max_retries == 7 # timeout - assert isinstance(self.client.timeout, httpx.Timeout) - copied = self.client.copy(timeout=None) + assert isinstance(async_client.timeout, httpx.Timeout) + copied = async_client.copy(timeout=None) assert copied.timeout is None - assert isinstance(self.client.timeout, httpx.Timeout) + assert isinstance(async_client.timeout, httpx.Timeout) - def test_copy_default_headers(self) -> None: + async def test_copy_default_headers(self) -> None: client = AsyncOrb( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} ) @@ -827,8 +1148,9 @@ def test_copy_default_headers(self) -> None: match="`default_headers` and `set_default_headers` arguments are mutually exclusive", ): client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) + await client.close() - def test_copy_default_query(self) -> None: + async def test_copy_default_query(self) -> None: client = AsyncOrb( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"foo": "bar"} ) @@ -864,13 +1186,15 @@ def test_copy_default_query(self) -> None: ): client.copy(set_default_query={}, default_query={"foo": "Bar"}) - def test_copy_signature(self) -> None: + await client.close() + + def test_copy_signature(self, async_client: AsyncOrb) -> None: # ensure the same parameters that can be passed to the client are defined in the `.copy()` method init_signature = inspect.signature( # mypy doesn't like that we access the `__init__` property. - self.client.__init__, # type: ignore[misc] + async_client.__init__, # type: ignore[misc] ) - copy_signature = inspect.signature(self.client.copy) + copy_signature = inspect.signature(async_client.copy) exclude_params = {"transport", "proxies", "_strict_response_validation"} for name in init_signature.parameters.keys(): @@ -880,12 +1204,13 @@ def test_copy_signature(self) -> None: copy_param = copy_signature.parameters.get(name) assert copy_param is not None, f"copy() signature is missing the {name} param" - def test_copy_build_request(self) -> None: + @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") + def test_copy_build_request(self, async_client: AsyncOrb) -> None: options = FinalRequestOptions(method="get", url="/foo") def build_request(options: FinalRequestOptions) -> None: - client = self.client.copy() - client._build_request(options) + client_copy = async_client.copy() + client_copy._build_request(options) # ensure that the machinery is warmed up before tracing starts. build_request(options) @@ -942,12 +1267,12 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic print(frame) raise AssertionError() - async def test_request_timeout(self) -> None: - request = self.client._build_request(FinalRequestOptions(method="get", url="/foo")) + async def test_request_timeout(self, async_client: AsyncOrb) -> None: + request = async_client._build_request(FinalRequestOptions(method="get", url="/foo")) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT - request = self.client._build_request( + request = async_client._build_request( FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)) ) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore @@ -962,6 +1287,8 @@ async def test_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(0) + await client.close() + async def test_http_client_timeout_option(self) -> None: # custom timeout given to the httpx client should be used async with httpx.AsyncClient(timeout=None) as http_client: @@ -973,6 +1300,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(None) + await client.close() + # no timeout given to the httpx client should not use the httpx default async with httpx.AsyncClient() as http_client: client = AsyncOrb( @@ -983,6 +1312,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT + await client.close() + # explicitly passing the default timeout currently results in it being ignored async with httpx.AsyncClient(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: client = AsyncOrb( @@ -993,6 +1324,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT # our default + await client.close() + def test_invalid_http_client(self) -> None: with pytest.raises(TypeError, match="Invalid `http_client` arg"): with httpx.Client() as http_client: @@ -1003,15 +1336,15 @@ def test_invalid_http_client(self) -> None: http_client=cast(Any, http_client), ) - def test_default_headers_option(self) -> None: - client = AsyncOrb( + async def test_default_headers_option(self) -> None: + test_client = AsyncOrb( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} ) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "bar" assert request.headers.get("x-stainless-lang") == "python" - client2 = AsyncOrb( + test_client2 = AsyncOrb( base_url=base_url, api_key=api_key, _strict_response_validation=True, @@ -1020,20 +1353,24 @@ def test_default_headers_option(self) -> None: "X-Stainless-Lang": "my-overriding-header", }, ) - request = client2._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "stainless" assert request.headers.get("x-stainless-lang") == "my-overriding-header" + await test_client.close() + await test_client2.close() + def test_validate_headers(self) -> None: client = AsyncOrb(base_url=base_url, api_key=api_key, _strict_response_validation=True) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("Authorization") == f"Bearer {api_key}" with pytest.raises(OrbError): - client2 = AsyncOrb(base_url=base_url, api_key=None, _strict_response_validation=True) + with update_env(**{"ORB_API_KEY": Omit()}): + client2 = AsyncOrb(base_url=base_url, api_key=None, _strict_response_validation=True) _ = client2 - def test_default_query_option(self) -> None: + async def test_default_query_option(self) -> None: client = AsyncOrb( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"} ) @@ -1045,14 +1382,40 @@ def test_default_query_option(self) -> None: FinalRequestOptions( method="get", url="/foo", - params={"foo": "baz", "query_param": "overriden"}, + params={"foo": "baz", "query_param": "overridden"}, ) ) url = httpx.URL(request.url) - assert dict(url.params) == {"foo": "baz", "query_param": "overriden"} + assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} - def test_request_extra_json(self) -> None: - request = self.client._build_request( + await client.close() + + async def test_hardcoded_query_params_in_url(self, async_client: AsyncOrb) -> None: + request = async_client._build_request(FinalRequestOptions(method="get", url="/foo?beta=true")) + url = httpx.URL(request.url) + assert dict(url.params) == {"beta": "true"} + + request = async_client._build_request( + FinalRequestOptions( + method="get", + url="/foo?beta=true", + params={"limit": "10", "page": "abc"}, + ) + ) + url = httpx.URL(request.url) + assert dict(url.params) == {"beta": "true", "limit": "10", "page": "abc"} + + request = async_client._build_request( + FinalRequestOptions( + method="get", + url="/files/a%2Fb?beta=true", + params={"limit": "10"}, + ) + ) + assert request.url.raw_path == b"/files/a%2Fb?beta=true&limit=10" + + def test_request_extra_json(self, client: Orb) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1063,7 +1426,7 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": False} - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1074,7 +1437,7 @@ def test_request_extra_json(self) -> None: assert data == {"baz": False} # `extra_json` takes priority over `json_data` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1085,8 +1448,8 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": None} - def test_request_extra_headers(self) -> None: - request = self.client._build_request( + def test_request_extra_headers(self, client: Orb) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1096,7 +1459,7 @@ def test_request_extra_headers(self) -> None: assert request.headers.get("X-Foo") == "Foo" # `extra_headers` takes priority over `default_headers` when keys clash - request = self.client.with_options(default_headers={"X-Bar": "true"})._build_request( + request = client.with_options(default_headers={"X-Bar": "true"})._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1107,8 +1470,8 @@ def test_request_extra_headers(self) -> None: ) assert request.headers.get("X-Bar") == "false" - def test_request_extra_query(self) -> None: - request = self.client._build_request( + def test_request_extra_query(self, client: Orb) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1121,7 +1484,7 @@ def test_request_extra_query(self) -> None: assert params == {"my_query_param": "Foo"} # if both `query` and `extra_query` are given, they are merged - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1135,7 +1498,7 @@ def test_request_extra_query(self) -> None: assert params == {"bar": "1", "foo": "2"} # `extra_query` takes priority over `query` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1151,7 +1514,7 @@ def test_request_extra_query(self) -> None: def test_multipart_repeating_array(self, async_client: AsyncOrb) -> None: request = async_client._build_request( FinalRequestOptions.construct( - method="get", + method="post", url="/foo", headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, json_data={"array": ["foo", "bar"]}, @@ -1178,7 +1541,73 @@ def test_multipart_repeating_array(self, async_client: AsyncOrb) -> None: ] @pytest.mark.respx(base_url=base_url) - async def test_basic_union_response(self, respx_mock: MockRouter) -> None: + async def test_binary_content_upload(self, respx_mock: MockRouter, async_client: AsyncOrb) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + response = await async_client.post( + "/upload", + content=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + + async def test_binary_content_upload_with_asynciterator(self) -> None: + file_content = b"Hello, this is a test file." + counter = Counter() + iterator = _make_async_iterator([file_content], counter=counter) + + async def mock_handler(request: httpx.Request) -> httpx.Response: + assert counter.value == 0, "the request body should not have been read" + return httpx.Response(200, content=await request.aread()) + + async with AsyncOrb( + base_url=base_url, + api_key=api_key, + _strict_response_validation=True, + http_client=httpx.AsyncClient(transport=MockTransport(handler=mock_handler)), + ) as client: + response = await client.post( + "/upload", + content=iterator, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + assert counter.value == 1 + + @pytest.mark.respx(base_url=base_url) + async def test_binary_content_upload_with_body_is_deprecated( + self, respx_mock: MockRouter, async_client: AsyncOrb + ) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + with pytest.deprecated_call( + match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead." + ): + response = await async_client.post( + "/upload", + body=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + + @pytest.mark.respx(base_url=base_url) + async def test_basic_union_response(self, respx_mock: MockRouter, async_client: AsyncOrb) -> None: class Model1(BaseModel): name: str @@ -1187,12 +1616,12 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" @pytest.mark.respx(base_url=base_url) - async def test_union_response_different_types(self, respx_mock: MockRouter) -> None: + async def test_union_response_different_types(self, respx_mock: MockRouter, async_client: AsyncOrb) -> None: """Union of objects with the same field name using a different type""" class Model1(BaseModel): @@ -1203,18 +1632,20 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model1) assert response.foo == 1 @pytest.mark.respx(base_url=base_url) - async def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter) -> None: + async def test_non_application_json_content_type_for_json_data( + self, respx_mock: MockRouter, async_client: AsyncOrb + ) -> None: """ Response that sets Content-Type to something other than application/json but returns json data """ @@ -1230,29 +1661,29 @@ class Model(BaseModel): ) ) - response = await self.client.get("/foo", cast_to=Model) + response = await async_client.get("/foo", cast_to=Model) assert isinstance(response, Model) assert response.foo == 2 @pytest.mark.respx(base_url=base_url) - async def test_idempotency_header_options(self, respx_mock: MockRouter) -> None: + async def test_idempotency_header_options(self, respx_mock: MockRouter, async_client: AsyncOrb) -> None: respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={})) - response = await self.client.post("/foo", cast_to=httpx.Response) + response = await async_client.post("/foo", cast_to=httpx.Response) header = response.request.headers.get("Idempotency-Key") assert header is not None assert header.startswith("stainless-python-retry") # explicit header - response = await self.client.post( + response = await async_client.post( "/foo", cast_to=httpx.Response, options=make_request_options(extra_headers={"Idempotency-Key": "custom-key"}), ) assert response.request.headers.get("Idempotency-Key") == "custom-key" - response = await self.client.post( + response = await async_client.post( "/foo", cast_to=httpx.Response, options=make_request_options(extra_headers={"idempotency-key": "custom-key"}), @@ -1260,12 +1691,12 @@ async def test_idempotency_header_options(self, respx_mock: MockRouter) -> None: assert response.request.headers.get("Idempotency-Key") == "custom-key" # custom argument - response = await self.client.post( + response = await async_client.post( "/foo", cast_to=httpx.Response, options=make_request_options(idempotency_key="custom-key") ) assert response.request.headers.get("Idempotency-Key") == "custom-key" - def test_base_url_setter(self) -> None: + async def test_base_url_setter(self) -> None: client = AsyncOrb(base_url="https://example.com/from_init", api_key=api_key, _strict_response_validation=True) assert client.base_url == "https://example.com/from_init/" @@ -1273,7 +1704,9 @@ def test_base_url_setter(self) -> None: assert client.base_url == "https://example.com/from_setter/" - def test_base_url_env(self) -> None: + await client.close() + + async def test_base_url_env(self) -> None: with update_env(ORB_BASE_URL="http://localhost:5000/from/env"): client = AsyncOrb(api_key=api_key, _strict_response_validation=True) assert client.base_url == "http://localhost:5000/from/env/" @@ -1291,7 +1724,7 @@ def test_base_url_env(self) -> None: ], ids=["standard", "custom http client"], ) - def test_base_url_trailing_slash(self, client: AsyncOrb) -> None: + async def test_base_url_trailing_slash(self, client: AsyncOrb) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1300,6 +1733,7 @@ def test_base_url_trailing_slash(self, client: AsyncOrb) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + await client.close() @pytest.mark.parametrize( "client", @@ -1314,7 +1748,7 @@ def test_base_url_trailing_slash(self, client: AsyncOrb) -> None: ], ids=["standard", "custom http client"], ) - def test_base_url_no_trailing_slash(self, client: AsyncOrb) -> None: + async def test_base_url_no_trailing_slash(self, client: AsyncOrb) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1323,6 +1757,7 @@ def test_base_url_no_trailing_slash(self, client: AsyncOrb) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + await client.close() @pytest.mark.parametrize( "client", @@ -1337,7 +1772,7 @@ def test_base_url_no_trailing_slash(self, client: AsyncOrb) -> None: ], ids=["standard", "custom http client"], ) - def test_absolute_request_url(self, client: AsyncOrb) -> None: + async def test_absolute_request_url(self, client: AsyncOrb) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1346,42 +1781,45 @@ def test_absolute_request_url(self, client: AsyncOrb) -> None: ), ) assert request.url == "https://myapi.com/foo" + await client.close() async def test_copied_client_does_not_close_http(self) -> None: - client = AsyncOrb(base_url=base_url, api_key=api_key, _strict_response_validation=True) - assert not client.is_closed() + test_client = AsyncOrb(base_url=base_url, api_key=api_key, _strict_response_validation=True) + assert not test_client.is_closed() - copied = client.copy() - assert copied is not client + copied = test_client.copy() + assert copied is not test_client del copied await asyncio.sleep(0.2) - assert not client.is_closed() + assert not test_client.is_closed() async def test_client_context_manager(self) -> None: - client = AsyncOrb(base_url=base_url, api_key=api_key, _strict_response_validation=True) - async with client as c2: - assert c2 is client + test_client = AsyncOrb(base_url=base_url, api_key=api_key, _strict_response_validation=True) + async with test_client as c2: + assert c2 is test_client assert not c2.is_closed() - assert not client.is_closed() - assert client.is_closed() + assert not test_client.is_closed() + assert test_client.is_closed() @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_client_response_validation_error(self, respx_mock: MockRouter) -> None: + async def test_client_response_validation_error(self, respx_mock: MockRouter, async_client: AsyncOrb) -> None: class Model(BaseModel): foo: str respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) with pytest.raises(APIResponseValidationError) as exc: - await self.client.get("/foo", cast_to=Model) + await async_client.get("/foo", cast_to=Model) assert isinstance(exc.value.__cause__, ValidationError) + async def test_client_max_retries_validation(self) -> None: + with pytest.raises(TypeError, match=r"max_retries cannot be None"): + AsyncOrb(base_url=base_url, api_key=api_key, _strict_response_validation=True, max_retries=cast(Any, None)) + @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio async def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None: class Model(BaseModel): name: str @@ -1393,11 +1831,14 @@ class Model(BaseModel): with pytest.raises(APIResponseValidationError): await strict_client.get("/foo", cast_to=Model) - client = AsyncOrb(base_url=base_url, api_key=api_key, _strict_response_validation=False) + non_strict_client = AsyncOrb(base_url=base_url, api_key=api_key, _strict_response_validation=False) - response = await client.get("/foo", cast_to=Model) + response = await non_strict_client.get("/foo", cast_to=Model) assert isinstance(response, str) # type: ignore[unreachable] + await strict_client.close() + await non_strict_client.close() + @pytest.mark.parametrize( "remaining_retries,retry_after,timeout", [ @@ -1416,44 +1857,202 @@ 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)) - @pytest.mark.asyncio - async def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str, timeout: float) -> None: - client = AsyncOrb(base_url=base_url, api_key=api_key, _strict_response_validation=True) - + async def test_parse_retry_after_header( + self, remaining_retries: int, retry_after: str, timeout: float, async_client: AsyncOrb + ) -> None: headers = httpx.Headers({"retry-after": retry_after}) options = FinalRequestOptions(method="get", url="/foo", max_retries=3) - calculated = client._calculate_retry_timeout(remaining_retries, options, headers) + calculated = async_client._calculate_retry_timeout(remaining_retries, options, headers) assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] @mock.patch("orb._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncOrb) -> None: respx_mock.post("/customers").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - await self.client.post( - "/customers", - body=cast(object, dict(email="example-customer@withorb.com", name="My Customer")), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) + await async_client.customers.with_streaming_response.create( + email="dev@stainless.com", name="x" + ).__aenter__() - assert _get_open_connections(self.client) == 0 + assert _get_open_connections(async_client) == 0 @mock.patch("orb._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncOrb) -> None: respx_mock.post("/customers").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - await self.client.post( - "/customers", - body=cast(object, dict(email="example-customer@withorb.com", name="My Customer")), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, + await async_client.customers.with_streaming_response.create( + email="dev@stainless.com", name="x" + ).__aenter__() + assert _get_open_connections(async_client) == 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.parametrize("failure_mode", ["status", "exception"]) + async def test_retries_taken( + 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) + + nb_retries = 0 + + 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="dev@stainless.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) + 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@stainless.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) + 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@stainless.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) + @pytest.mark.respx(base_url=base_url) + async def test_retries_taken_new_response_class( + 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) + + async with client.customers.with_streaming_response.create(email="dev@stainless.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 + + async def test_get_platform(self) -> None: + platform = await asyncify(get_platform)() + assert isinstance(platform, (str, OtherPlatform)) + + async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: + # Test that the proxy environment variables are set correctly + monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + # Delete in case our environment has any proxy env vars set + monkeypatch.delenv("HTTP_PROXY", raising=False) + monkeypatch.delenv("ALL_PROXY", raising=False) + monkeypatch.delenv("NO_PROXY", raising=False) + monkeypatch.delenv("http_proxy", raising=False) + monkeypatch.delenv("https_proxy", raising=False) + monkeypatch.delenv("all_proxy", raising=False) + monkeypatch.delenv("no_proxy", raising=False) + + client = DefaultAsyncHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + async def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultAsyncHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + + @pytest.mark.respx(base_url=base_url) + async def test_follow_redirects(self, respx_mock: MockRouter, async_client: AsyncOrb) -> None: + # Test that the default follow_redirects=True allows following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) + + response = await async_client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + assert response.status_code == 200 + assert response.json() == {"status": "ok"} + + @pytest.mark.respx(base_url=base_url) + async def test_follow_redirects_disabled(self, respx_mock: MockRouter, async_client: AsyncOrb) -> None: + # Test that follow_redirects=False prevents following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + + with pytest.raises(APIStatusError) as exc_info: + await async_client.post( + "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response ) - assert _get_open_connections(self.client) == 0 + assert exc_info.value.response.status_code == 302 + assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" diff --git a/tests/test_deepcopy.py b/tests/test_deepcopy.py deleted file mode 100644 index 1a6048b8..00000000 --- a/tests/test_deepcopy.py +++ /dev/null @@ -1,59 +0,0 @@ -from orb._utils import deepcopy_minimal - - -def assert_different_identities(obj1: object, obj2: object) -> None: - assert obj1 == obj2 - assert id(obj1) != id(obj2) - - -def test_simple_dict() -> None: - obj1 = {"foo": "bar"} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - - -def test_nested_dict() -> None: - obj1 = {"foo": {"bar": True}} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert_different_identities(obj1["foo"], obj2["foo"]) - - -def test_complex_nested_dict() -> None: - obj1 = {"foo": {"bar": [{"hello": "world"}]}} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert_different_identities(obj1["foo"], obj2["foo"]) - assert_different_identities(obj1["foo"]["bar"], obj2["foo"]["bar"]) - assert_different_identities(obj1["foo"]["bar"][0], obj2["foo"]["bar"][0]) - - -def test_simple_list() -> None: - obj1 = ["a", "b", "c"] - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - - -def test_nested_list() -> None: - obj1 = ["a", [1, 2, 3]] - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert_different_identities(obj1[1], obj2[1]) - - -class MyObject: - ... - - -def test_ignores_other_types() -> None: - # custom classes - my_obj = MyObject() - obj1 = {"foo": my_obj} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert obj1["foo"] is my_obj - - # tuples - obj3 = ("a", "b") - obj4 = deepcopy_minimal(obj3) - assert obj3 is obj4 diff --git a/tests/test_extract_files.py b/tests/test_extract_files.py index 722b1a6c..180faff0 100644 --- a/tests/test_extract_files.py +++ b/tests/test_extract_files.py @@ -4,7 +4,7 @@ import pytest -from orb._types import FileTypes +from orb._types import FileTypes, ArrayFormat from orb._utils import extract_files @@ -35,6 +35,12 @@ def test_multiple_files() -> None: assert query == {"documents": [{}, {}]} +def test_top_level_file_array() -> None: + query = {"files": [b"file one", b"file two"], "title": "hello"} + assert extract_files(query, paths=[["files", ""]]) == [("files[]", b"file one"), ("files[]", b"file two")] + assert query == {"title": "hello"} + + @pytest.mark.parametrize( "query,paths,expected", [ @@ -62,3 +68,24 @@ def test_ignores_incorrect_paths( expected: list[tuple[str, FileTypes]], ) -> None: assert extract_files(query, paths=paths) == expected + + +@pytest.mark.parametrize( + "array_format,expected_top_level,expected_nested", + [ + ("brackets", [("files[]", b"a"), ("files[]", b"b")], [("items[][file]", b"a"), ("items[][file]", b"b")]), + ("repeat", [("files", b"a"), ("files", b"b")], [("items[file]", b"a"), ("items[file]", b"b")]), + ("comma", [("files", b"a"), ("files", b"b")], [("items[file]", b"a"), ("items[file]", b"b")]), + ("indices", [("files[0]", b"a"), ("files[1]", b"b")], [("items[0][file]", b"a"), ("items[1][file]", b"b")]), + ], +) +def test_array_format_controls_file_field_names( + array_format: ArrayFormat, + expected_top_level: list[tuple[str, FileTypes]], + expected_nested: list[tuple[str, FileTypes]], +) -> None: + top_level = {"files": [b"a", b"b"]} + assert extract_files(top_level, paths=[["files", ""]], array_format=array_format) == expected_top_level + + nested = {"items": [{"file": b"a"}, {"file": b"b"}]} + assert extract_files(nested, paths=[["items", "", "file"]], array_format=array_format) == expected_nested diff --git a/tests/test_files.py b/tests/test_files.py index b84f4e26..20e2990c 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -4,7 +4,8 @@ import pytest from dirty_equals import IsDict, IsList, IsBytes, IsTuple -from orb._files import to_httpx_files, async_to_httpx_files +from orb._files import to_httpx_files, deepcopy_with_paths, async_to_httpx_files +from orb._utils import extract_files readme_path = Path(__file__).parent.parent.joinpath("README.md") @@ -49,3 +50,99 @@ def test_string_not_allowed() -> None: "file": "foo", # type: ignore } ) + + +def assert_different_identities(obj1: object, obj2: object) -> None: + assert obj1 == obj2 + assert obj1 is not obj2 + + +class TestDeepcopyWithPaths: + def test_copies_top_level_dict(self) -> None: + original = {"file": b"data", "other": "value"} + result = deepcopy_with_paths(original, [["file"]]) + assert_different_identities(result, original) + + def test_file_value_is_same_reference(self) -> None: + file_bytes = b"contents" + original = {"file": file_bytes} + result = deepcopy_with_paths(original, [["file"]]) + assert_different_identities(result, original) + assert result["file"] is file_bytes + + def test_list_popped_wholesale(self) -> None: + files = [b"f1", b"f2"] + original = {"files": files, "title": "t"} + result = deepcopy_with_paths(original, [["files", ""]]) + assert_different_identities(result, original) + result_files = result["files"] + assert isinstance(result_files, list) + assert_different_identities(result_files, files) + + def test_nested_array_path_copies_list_and_elements(self) -> None: + elem1 = {"file": b"f1", "extra": 1} + elem2 = {"file": b"f2", "extra": 2} + original = {"items": [elem1, elem2]} + result = deepcopy_with_paths(original, [["items", "", "file"]]) + assert_different_identities(result, original) + result_items = result["items"] + assert isinstance(result_items, list) + assert_different_identities(result_items, original["items"]) + assert_different_identities(result_items[0], elem1) + assert_different_identities(result_items[1], elem2) + + def test_empty_paths_returns_same_object(self) -> None: + original = {"foo": "bar"} + result = deepcopy_with_paths(original, []) + assert result is original + + def test_multiple_paths(self) -> None: + f1 = b"file1" + f2 = b"file2" + original = {"a": f1, "b": f2, "c": "unchanged"} + result = deepcopy_with_paths(original, [["a"], ["b"]]) + assert_different_identities(result, original) + assert result["a"] is f1 + assert result["b"] is f2 + assert result["c"] is original["c"] + + def test_extract_files_does_not_mutate_original_top_level(self) -> None: + file_bytes = b"contents" + original = {"file": file_bytes, "other": "value"} + + copied = deepcopy_with_paths(original, [["file"]]) + extracted = extract_files(copied, paths=[["file"]]) + + assert extracted == [("file", file_bytes)] + assert original == {"file": file_bytes, "other": "value"} + assert copied == {"other": "value"} + + def test_extract_files_does_not_mutate_original_nested_array_path(self) -> None: + file1 = b"f1" + file2 = b"f2" + original = { + "items": [ + {"file": file1, "extra": 1}, + {"file": file2, "extra": 2}, + ], + "title": "example", + } + + copied = deepcopy_with_paths(original, [["items", "", "file"]]) + extracted = extract_files(copied, paths=[["items", "", "file"]]) + + assert [entry for _, entry in extracted] == [file1, file2] + assert original == { + "items": [ + {"file": file1, "extra": 1}, + {"file": file2, "extra": 2}, + ], + "title": "example", + } + assert copied == { + "items": [ + {"extra": 1}, + {"extra": 2}, + ], + "title": "example", + } diff --git a/tests/test_legacy_response.py b/tests/test_legacy_response.py index fe9c205a..3cabbaf5 100644 --- a/tests/test_legacy_response.py +++ b/tests/test_legacy_response.py @@ -1,5 +1,5 @@ import json -from typing import cast +from typing import Any, Union, cast from typing_extensions import Annotated import httpx @@ -12,8 +12,7 @@ from orb._legacy_response import LegacyAPIResponse -class PydanticModel(pydantic.BaseModel): - ... +class PydanticModel(pydantic.BaseModel): ... def test_response_parse_mismatched_basemodel(client: Orb) -> None: @@ -33,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"), @@ -82,3 +106,23 @@ def test_response_parse_annotated_type(client: Orb) -> None: ) assert obj.foo == "hello!" assert obj.bar == 2 + + +class OtherModel(pydantic.BaseModel): + a: str + + +@pytest.mark.parametrize("client", [False], indirect=True) # loose validation +def test_response_parse_expect_model_union_non_json_content(client: Orb) -> None: + response = LegacyAPIResponse( + raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = response.parse(to=cast(Any, Union[CustomModel, OtherModel])) + assert isinstance(obj, str) + assert obj == "foo" diff --git a/tests/test_models.py b/tests/test_models.py index 512d9946..6a712787 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,15 +1,16 @@ import json -from typing import Any, Dict, List, Union, Optional, cast +from typing import TYPE_CHECKING, Any, Dict, List, Union, Iterable, Optional, cast from datetime import datetime, timezone -from typing_extensions import Literal, Annotated +from collections import deque +from typing_extensions import Literal, Annotated, TypedDict, TypeAliasType import pytest import pydantic from pydantic import Field from orb._utils import PropertyInfo -from orb._compat import PYDANTIC_V2, parse_obj, model_dump, model_json -from orb._models import BaseModel, construct_type +from orb._compat import PYDANTIC_V1, parse_obj, model_dump, model_json +from orb._models import DISCRIMINATOR_CACHE, BaseModel, EagerIterable, construct_type class BasicModel(BaseModel): @@ -31,7 +32,7 @@ class NestedModel(BaseModel): # mismatched types m = NestedModel.construct(nested="hello!") - assert m.nested == "hello!" + assert cast(Any, m.nested) == "hello!" def test_optional_nested_model() -> None: @@ -48,7 +49,7 @@ class NestedModel(BaseModel): # mismatched types m3 = NestedModel.construct(nested={"foo"}) assert isinstance(cast(Any, m3.nested), set) - assert m3.nested == {"foo"} + assert cast(Any, m3.nested) == {"foo"} def test_list_nested_model() -> None: @@ -245,7 +246,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) @@ -294,12 +295,12 @@ class Model(BaseModel): assert cast(bool, m.foo) is True m = Model.construct(foo={"name": 3}) - if PYDANTIC_V2: - assert isinstance(m.foo, Submodel1) - assert m.foo.name == 3 # type: ignore - else: + if PYDANTIC_V1: assert isinstance(m.foo, Submodel2) assert m.foo.name == "3" + else: + assert isinstance(m.foo, Submodel1) + assert m.foo.name == 3 # type: ignore def test_list_of_unions() -> None: @@ -323,7 +324,7 @@ class Model(BaseModel): assert len(m.items) == 2 assert isinstance(m.items[0], Submodel1) assert m.items[0].level == -1 - assert m.items[1] == 156 + assert cast(Any, m.items[1]) == 156 def test_union_of_lists() -> None: @@ -355,7 +356,7 @@ class Model(BaseModel): assert len(m.items) == 2 assert isinstance(m.items[0], SubModel1) assert m.items[0].level == -1 - assert m.items[1] == 156 + assert cast(Any, m.items[1]) == 156 def test_dict_of_union() -> None: @@ -426,10 +427,10 @@ class Model(BaseModel): expected = datetime(2019, 12, 27, 18, 11, 19, 117000, tzinfo=timezone.utc) - if PYDANTIC_V2: - expected_json = '{"created_at":"2019-12-27T18:11:19.117000Z"}' - else: + if PYDANTIC_V1: expected_json = '{"created_at": "2019-12-27T18:11:19.117000+00:00"}' + else: + expected_json = '{"created_at":"2019-12-27T18:11:19.117000Z"}' model = Model.construct(created_at="2019-12-27T18:11:19.117Z") assert model.created_at == expected @@ -492,15 +493,50 @@ class Model(BaseModel): resource_id: Optional[str] = None m = Model.construct() + assert m.resource_id is None assert "resource_id" not in m.model_fields_set m = Model.construct(resource_id=None) + assert m.resource_id is None assert "resource_id" in m.model_fields_set m = Model.construct(resource_id="foo") + assert m.resource_id == "foo" assert "resource_id" in m.model_fields_set +def test_to_dict() -> None: + class Model(BaseModel): + foo: Optional[str] = Field(alias="FOO", default=None) + + m = Model(FOO="hello") + assert m.to_dict() == {"FOO": "hello"} + assert m.to_dict(use_api_names=False) == {"foo": "hello"} + + m2 = Model() + assert m2.to_dict() == {} + assert m2.to_dict(exclude_unset=False) == {"FOO": None} + assert m2.to_dict(exclude_unset=False, exclude_none=True) == {} + assert m2.to_dict(exclude_unset=False, exclude_defaults=True) == {} + + m3 = Model(FOO=None) + assert m3.to_dict() == {"FOO": None} + assert m3.to_dict(exclude_none=True) == {} + assert m3.to_dict(exclude_defaults=True) == {} + + 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} + + if PYDANTIC_V1: + with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): + m.to_dict(warnings=False) + + def test_forwards_compat_model_dump_method() -> None: class Model(BaseModel): foo: Optional[str] = Field(alias="FOO", default=None) @@ -521,10 +557,7 @@ class Model(BaseModel): assert m3.model_dump() == {"foo": None} 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") - + if PYDANTIC_V1: with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): m.model_dump(round_trip=True) @@ -532,6 +565,42 @@ 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) + + m = Model(FOO="hello") + assert json.loads(m.to_json()) == {"FOO": "hello"} + assert json.loads(m.to_json(use_api_names=False)) == {"foo": "hello"} + + if PYDANTIC_V1: + assert m.to_json(indent=None) == '{"FOO": "hello"}' + else: + assert m.to_json(indent=None) == '{"FOO":"hello"}' + + m2 = Model() + assert json.loads(m2.to_json()) == {} + assert json.loads(m2.to_json(exclude_unset=False)) == {"FOO": None} + assert json.loads(m2.to_json(exclude_unset=False, exclude_none=True)) == {} + assert json.loads(m2.to_json(exclude_unset=False, exclude_defaults=True)) == {} + + m3 = Model(FOO=None) + assert json.loads(m3.to_json()) == {"FOO": None} + assert json.loads(m3.to_json(exclude_none=True)) == {} + + if PYDANTIC_V1: + with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): + m.to_json(warnings=False) + + def test_forwards_compat_model_dump_json_method() -> None: class Model(BaseModel): foo: Optional[str] = Field(alias="FOO", default=None) @@ -554,7 +623,7 @@ class Model(BaseModel): assert json.loads(m3.model_dump_json()) == {"foo": None} assert json.loads(m3.model_dump_json(exclude_none=True)) == {} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): m.model_dump_json(round_trip=True) @@ -611,12 +680,12 @@ class B(BaseModel): ) assert isinstance(m, A) assert m.type == "a" - if PYDANTIC_V2: - assert m.data == 100 # type: ignore[comparison-overlap] - else: + if PYDANTIC_V1: # pydantic v1 automatically converts inputs to strings # if the expected type is a str assert m.data == "100" + else: + assert m.data == 100 # type: ignore[comparison-overlap] def test_discriminated_unions_unknown_variant() -> None: @@ -700,12 +769,12 @@ class B(BaseModel): ) assert isinstance(m, A) assert m.foo_type == "a" - if PYDANTIC_V2: - assert m.data == 100 # type: ignore[comparison-overlap] - else: + if PYDANTIC_V1: # pydantic v1 automatically converts inputs to strings # if the expected type is a str assert m.data == "100" + else: + assert m.data == 100 # type: ignore[comparison-overlap] def test_discriminated_unions_overlapping_discriminators_invalid_data() -> None: @@ -741,7 +810,7 @@ class B(BaseModel): UnionType = cast(Any, Union[A, B]) - assert not hasattr(UnionType, "__discriminator__") + assert not DISCRIMINATOR_CACHE.get(UnionType) m = construct_type( value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")]) @@ -750,7 +819,7 @@ class B(BaseModel): assert m.type == "b" assert m.data == "foo" # type: ignore[comparison-overlap] - discriminator = UnionType.__discriminator__ + discriminator = DISCRIMINATOR_CACHE.get(UnionType) assert discriminator is not None m = construct_type( @@ -762,4 +831,187 @@ class B(BaseModel): # if the discriminator details object stays the same between invocations then # we hit the cache - assert UnionType.__discriminator__ is discriminator + assert DISCRIMINATOR_CACHE.get(UnionType) is discriminator + + +@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") +def test_type_alias_type() -> None: + Alias = TypeAliasType("Alias", str) # pyright: ignore + + class Model(BaseModel): + alias: Alias + union: Union[int, Alias] + + m = construct_type(value={"alias": "foo", "union": "bar"}, type_=Model) + assert isinstance(m, Model) + assert isinstance(m.alias, str) + assert m.alias == "foo" + assert isinstance(m.union, str) + assert m.union == "bar" + + +@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") +def test_field_named_cls() -> None: + class Model(BaseModel): + cls: str + + m = construct_type(value={"cls": "foo"}, type_=Model) + assert isinstance(m, Model) + assert isinstance(m.cls, str) + + +def test_discriminated_union_case() -> None: + class A(BaseModel): + type: Literal["a"] + + data: bool + + class B(BaseModel): + type: Literal["b"] + + data: List[Union[A, object]] + + class ModelA(BaseModel): + type: Literal["modelA"] + + data: int + + class ModelB(BaseModel): + type: Literal["modelB"] + + required: str + + data: Union[A, B] + + # when constructing ModelA | ModelB, value data doesn't match ModelB exactly - missing `required` + m = construct_type( + value={"type": "modelB", "data": {"type": "a", "data": True}}, + type_=cast(Any, Annotated[Union[ModelA, ModelB], PropertyInfo(discriminator="type")]), + ) + + assert isinstance(m, ModelB) + + +def test_nested_discriminated_union() -> None: + class InnerType1(BaseModel): + type: Literal["type_1"] + + class InnerModel(BaseModel): + inner_value: str + + class InnerType2(BaseModel): + type: Literal["type_2"] + some_inner_model: InnerModel + + class Type1(BaseModel): + base_type: Literal["base_type_1"] + value: Annotated[ + Union[ + InnerType1, + InnerType2, + ], + PropertyInfo(discriminator="type"), + ] + + class Type2(BaseModel): + base_type: Literal["base_type_2"] + + T = Annotated[ + Union[ + Type1, + Type2, + ], + PropertyInfo(discriminator="base_type"), + ] + + model = construct_type( + type_=T, + value={ + "base_type": "base_type_1", + "value": { + "type": "type_2", + }, + }, + ) + assert isinstance(model, Type1) + assert isinstance(model.value, InnerType2) + + +@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2 for now") +def test_extra_properties() -> None: + class Item(BaseModel): + prop: int + + class Model(BaseModel): + __pydantic_extra__: Dict[str, Item] = Field(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + + other: str + + if TYPE_CHECKING: + + def __getattr__(self, attr: str) -> Item: ... + + model = construct_type( + type_=Model, + value={ + "a": {"prop": 1}, + "other": "foo", + }, + ) + assert isinstance(model, Model) + assert model.a.prop == 1 + assert isinstance(model.a, Item) + assert model.other == "foo" + + +# NOTE: Workaround for Pydantic Iterable behavior. +# Iterable fields are replaced with a ValidatorIterator and may be consumed +# during serialization, which can cause subsequent dumps to return empty data. +# See: https://github.com/pydantic/pydantic/issues/9541 +@pytest.mark.parametrize( + "data, expected_validated", + [ + ([1, 2, 3], [1, 2, 3]), + ((1, 2, 3), (1, 2, 3)), + (set([1, 2, 3]), set([1, 2, 3])), + (iter([1, 2, 3]), [1, 2, 3]), + ([], []), + ((x for x in [1, 2, 3]), [1, 2, 3]), + (map(lambda x: x, [1, 2, 3]), [1, 2, 3]), + (frozenset([1, 2, 3]), frozenset([1, 2, 3])), + (deque([1, 2, 3]), deque([1, 2, 3])), + ], + ids=["list", "tuple", "set", "iterator", "empty", "generator", "map", "frozenset", "deque"], +) +@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2") +def test_iterable_construction(data: Iterable[int], expected_validated: Iterable[int]) -> None: + class TypeWithIterable(TypedDict): + items: EagerIterable[int] + + class Model(BaseModel): + data: TypeWithIterable + + m = Model.model_validate({"data": {"items": data}}) + assert m.data["items"] == expected_validated + + # Verify repeated dumps don't lose data (the original bug) + assert m.model_dump()["data"]["items"] == list(expected_validated) + assert m.model_dump()["data"]["items"] == list(expected_validated) + + +@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2") +def test_iterable_construction_str_falls_back_to_list() -> None: + # str is iterable (over chars), but str(list_of_chars) produces the list's repr + # rather than reconstructing a string from items. We special-case str to fall + # back to list instead of attempting reconstruction. + class TypeWithIterable(TypedDict): + items: EagerIterable[str] + + class Model(BaseModel): + data: TypeWithIterable + + m = Model.model_validate({"data": {"items": "hello"}}) + + # falls back to list of chars rather than calling str(["h", "e", "l", "l", "o"]) + assert m.data["items"] == ["h", "e", "l", "l", "o"] + assert m.model_dump()["data"]["items"] == ["h", "e", "l", "l", "o"] diff --git a/tests/test_response.py b/tests/test_response.py index e90e201b..db04a272 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -1,5 +1,5 @@ import json -from typing import List, cast +from typing import Any, List, Union, cast from typing_extensions import Annotated import httpx @@ -19,16 +19,13 @@ from orb._base_client import FinalRequestOptions -class ConcreteBaseAPIResponse(APIResponse[bytes]): - ... +class ConcreteBaseAPIResponse(APIResponse[bytes]): ... -class ConcreteAPIResponse(APIResponse[List[str]]): - ... +class ConcreteAPIResponse(APIResponse[List[str]]): ... -class ConcreteAsyncAPIResponse(APIResponse[httpx.Response]): - ... +class ConcreteAsyncAPIResponse(APIResponse[httpx.Response]): ... def test_extract_response_type_direct_classes() -> None: @@ -56,8 +53,7 @@ def test_extract_response_type_binary_response() -> None: assert extract_response_type(AsyncBinaryAPIResponse) == bytes -class PydanticModel(pydantic.BaseModel): - ... +class PydanticModel(pydantic.BaseModel): ... def test_response_parse_mismatched_basemodel(client: Orb) -> None: @@ -192,3 +188,90 @@ async def test_async_response_parse_annotated_type(async_client: AsyncOrb) -> No ) assert obj.foo == "hello!" 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 + + +@pytest.mark.parametrize("client", [False], indirect=True) # loose validation +def test_response_parse_expect_model_union_non_json_content(client: Orb) -> None: + response = APIResponse( + raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = response.parse(to=cast(Any, Union[CustomModel, OtherModel])) + assert isinstance(obj, str) + assert obj == "foo" + + +@pytest.mark.asyncio +@pytest.mark.parametrize("async_client", [False], indirect=True) # loose validation +async def test_async_response_parse_expect_model_union_non_json_content(async_client: AsyncOrb) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}), + client=async_client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = await response.parse(to=cast(Any, Union[CustomModel, OtherModel])) + assert isinstance(obj, str) + assert obj == "foo" diff --git a/tests/test_streaming.py b/tests/test_streaming.py index c8c7b692..79f4a65f 100644 --- a/tests/test_streaming.py +++ b/tests/test_streaming.py @@ -1,104 +1,248 @@ +from __future__ import annotations + from typing import Iterator, AsyncIterator +import httpx import pytest -from orb._streaming import SSEDecoder +from orb import Orb, AsyncOrb +from orb._streaming import Stream, AsyncStream, ServerSentEvent @pytest.mark.asyncio -async def test_basic_async() -> None: - async def body() -> AsyncIterator[str]: - yield "event: completion" - yield 'data: {"foo":true}' - yield "" - - async for sse in SSEDecoder().aiter(body()): - assert sse.event == "completion" - assert sse.json() == {"foo": True} +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_basic(sync: bool, client: Orb, async_client: AsyncOrb) -> None: + def body() -> Iterator[bytes]: + yield b"event: completion\n" + yield b'data: {"foo":true}\n' + yield b"\n" + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) -def test_basic() -> None: - def body() -> Iterator[str]: - yield "event: completion" - yield 'data: {"foo":true}' - yield "" - - it = SSEDecoder().iter(body()) - sse = next(it) + sse = await iter_next(iterator) assert sse.event == "completion" assert sse.json() == {"foo": True} - with pytest.raises(StopIteration): - next(it) + await assert_empty_iter(iterator) -def test_data_missing_event() -> None: - def body() -> Iterator[str]: - yield 'data: {"foo":true}' - yield "" +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_data_missing_event(sync: bool, client: Orb, async_client: AsyncOrb) -> None: + def body() -> Iterator[bytes]: + yield b'data: {"foo":true}\n' + yield b"\n" - it = SSEDecoder().iter(body()) - sse = next(it) + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) assert sse.event is None assert sse.json() == {"foo": True} - with pytest.raises(StopIteration): - next(it) + await assert_empty_iter(iterator) + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_event_missing_data(sync: bool, client: Orb, async_client: AsyncOrb) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b"\n" -def test_event_missing_data() -> None: - def body() -> Iterator[str]: - yield "event: ping" - yield "" + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) - it = SSEDecoder().iter(body()) - sse = next(it) + sse = await iter_next(iterator) assert sse.event == "ping" assert sse.data == "" - with pytest.raises(StopIteration): - next(it) + await assert_empty_iter(iterator) -def test_multiple_events() -> None: - def body() -> Iterator[str]: - yield "event: ping" - yield "" - yield "event: completion" - yield "" +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multiple_events(sync: bool, client: Orb, async_client: AsyncOrb) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b"\n" + yield b"event: completion\n" + yield b"\n" - it = SSEDecoder().iter(body()) + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) - sse = next(it) + sse = await iter_next(iterator) assert sse.event == "ping" assert sse.data == "" - sse = next(it) + sse = await iter_next(iterator) assert sse.event == "completion" assert sse.data == "" - with pytest.raises(StopIteration): - next(it) - - -def test_multiple_events_with_data() -> None: - def body() -> Iterator[str]: - yield "event: ping" - yield 'data: {"foo":true}' - yield "" - yield "event: completion" - yield 'data: {"bar":false}' - yield "" + await assert_empty_iter(iterator) - it = SSEDecoder().iter(body()) - sse = next(it) +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multiple_events_with_data(sync: bool, client: Orb, async_client: AsyncOrb) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b'data: {"foo":true}\n' + yield b"\n" + yield b"event: completion\n" + yield b'data: {"bar":false}\n' + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) assert sse.event == "ping" assert sse.json() == {"foo": True} - sse = next(it) + sse = await iter_next(iterator) assert sse.event == "completion" assert sse.json() == {"bar": False} - with pytest.raises(StopIteration): - next(it) + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multiple_data_lines_with_empty_line(sync: bool, client: Orb, async_client: AsyncOrb) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b"data: {\n" + yield b'data: "foo":\n' + yield b"data: \n" + yield b"data:\n" + yield b"data: true}\n" + yield b"\n\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.json() == {"foo": True} + assert sse.data == '{\n"foo":\n\n\ntrue}' + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_data_json_escaped_double_new_line(sync: bool, client: Orb, async_client: AsyncOrb) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b'data: {"foo": "my long\\n\\ncontent"}' + yield b"\n\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.json() == {"foo": "my long\n\ncontent"} + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multiple_data_lines(sync: bool, client: Orb, async_client: AsyncOrb) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b"data: {\n" + yield b'data: "foo":\n' + yield b"data: true}\n" + yield b"\n\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.json() == {"foo": True} + + await assert_empty_iter(iterator) + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_special_new_line_character( + sync: bool, + client: Orb, + async_client: AsyncOrb, +) -> None: + def body() -> Iterator[bytes]: + yield b'data: {"content":" culpa"}\n' + yield b"\n" + yield b'data: {"content":" \xe2\x80\xa8"}\n' + yield b"\n" + yield b'data: {"content":"foo"}\n' + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event is None + assert sse.json() == {"content": " culpa"} + + sse = await iter_next(iterator) + assert sse.event is None + assert sse.json() == {"content": " 
"} + + sse = await iter_next(iterator) + assert sse.event is None + assert sse.json() == {"content": "foo"} + + await assert_empty_iter(iterator) + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multi_byte_character_multiple_chunks( + sync: bool, + client: Orb, + async_client: AsyncOrb, +) -> None: + def body() -> Iterator[bytes]: + yield b'data: {"content":"' + # bytes taken from the string 'известни' and arbitrarily split + # so that some multi-byte characters span multiple chunks + yield b"\xd0" + yield b"\xb8\xd0\xb7\xd0" + yield b"\xb2\xd0\xb5\xd1\x81\xd1\x82\xd0\xbd\xd0\xb8" + yield b'"}\n' + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event is None + assert sse.json() == {"content": "известни"} + + +async def to_aiter(iter: Iterator[bytes]) -> AsyncIterator[bytes]: + for chunk in iter: + yield chunk + + +async def iter_next(iter: Iterator[ServerSentEvent] | AsyncIterator[ServerSentEvent]) -> ServerSentEvent: + if isinstance(iter, AsyncIterator): + return await iter.__anext__() + + return next(iter) + + +async def assert_empty_iter(iter: Iterator[ServerSentEvent] | AsyncIterator[ServerSentEvent]) -> None: + with pytest.raises((StopAsyncIteration, RuntimeError)): + await iter_next(iter) + + +def make_event_iterator( + content: Iterator[bytes], + *, + sync: bool, + client: Orb, + async_client: AsyncOrb, +) -> Iterator[ServerSentEvent] | AsyncIterator[ServerSentEvent]: + if sync: + return Stream(cast_to=object, client=client, response=httpx.Response(200, content=content))._iter_events() + + return AsyncStream( + cast_to=object, client=async_client, response=httpx.Response(200, content=to_aiter(content)) + )._iter_events() diff --git a/tests/test_transform.py b/tests/test_transform.py index 7d7e7341..f01d8ce0 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -2,20 +2,20 @@ import io import pathlib -from typing import Any, List, Union, TypeVar, Iterable, Optional, cast +from typing import Any, Dict, List, Union, TypeVar, Iterable, Optional, cast from datetime import date, datetime from typing_extensions import Required, Annotated, TypedDict import pytest -from orb._types import Base64FileInput +from orb._types import Base64FileInput, omit, not_given from orb._utils import ( PropertyInfo, transform as _transform, parse_datetime, async_transform as _async_transform, ) -from orb._compat import PYDANTIC_V2 +from orb._compat import PYDANTIC_V1 from orb._models import BaseModel _T = TypeVar("_T") @@ -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 = "+00:00" if PYDANTIC_V1 else "Z" 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 @@ -260,44 +275,46 @@ class MyModel(BaseModel): @parametrize @pytest.mark.asyncio async def test_pydantic_model_to_dictionary(use_async: bool) -> None: - assert await transform(MyModel(foo="hi!"), Any, use_async) == {"foo": "hi!"} - assert await transform(MyModel.construct(foo="hi!"), Any, use_async) == {"foo": "hi!"} + assert cast(Any, await transform(MyModel(foo="hi!"), Any, use_async)) == {"foo": "hi!"} + assert cast(Any, await transform(MyModel.construct(foo="hi!"), Any, use_async)) == {"foo": "hi!"} @parametrize @pytest.mark.asyncio async def test_pydantic_empty_model(use_async: bool) -> None: - assert await transform(MyModel.construct(), Any, use_async) == {} + assert cast(Any, await transform(MyModel.construct(), Any, use_async)) == {} @parametrize @pytest.mark.asyncio async def test_pydantic_unknown_field(use_async: bool) -> None: - assert await transform(MyModel.construct(my_untyped_field=True), Any, use_async) == {"my_untyped_field": True} + assert cast(Any, await transform(MyModel.construct(my_untyped_field=True), Any, use_async)) == { + "my_untyped_field": True + } @parametrize @pytest.mark.asyncio async def test_pydantic_mismatched_types(use_async: bool) -> None: model = MyModel.construct(foo=True) - if PYDANTIC_V2: + if PYDANTIC_V1: + params = await transform(model, Any, use_async) + else: with pytest.warns(UserWarning): params = await transform(model, Any, use_async) - else: - params = await transform(model, Any, use_async) - assert params == {"foo": True} + assert cast(Any, params) == {"foo": True} @parametrize @pytest.mark.asyncio async def test_pydantic_mismatched_object_type(use_async: bool) -> None: model = MyModel.construct(foo=MyModel.construct(hello="world")) - if PYDANTIC_V2: + if PYDANTIC_V1: + params = await transform(model, Any, use_async) + else: with pytest.warns(UserWarning): params = await transform(model, Any, use_async) - else: - params = await transform(model, Any, use_async) - assert params == {"foo": {"hello": "world"}} + assert cast(Any, params) == {"foo": {"hello": "world"}} class ModelNestedObjects(BaseModel): @@ -309,7 +326,7 @@ class ModelNestedObjects(BaseModel): async def test_pydantic_nested_objects(use_async: bool) -> None: model = ModelNestedObjects.construct(nested={"foo": "stainless"}) assert isinstance(model.nested, MyModel) - assert await transform(model, Any, use_async) == {"nested": {"foo": "stainless"}} + assert cast(Any, await transform(model, Any, use_async)) == {"nested": {"foo": "stainless"}} class ModelWithDefaultField(BaseModel): @@ -325,19 +342,19 @@ async def test_pydantic_default_field(use_async: bool) -> None: model = ModelWithDefaultField.construct() assert model.with_none_default is None assert model.with_str_default == "foo" - assert await transform(model, Any, use_async) == {} + assert cast(Any, await transform(model, Any, use_async)) == {} # should be included when the default value is explicitly given model = ModelWithDefaultField.construct(with_none_default=None, with_str_default="foo") assert model.with_none_default is None assert model.with_str_default == "foo" - assert await transform(model, Any, use_async) == {"with_none_default": None, "with_str_default": "foo"} + assert cast(Any, await transform(model, Any, use_async)) == {"with_none_default": None, "with_str_default": "foo"} # should be included when a non-default value is explicitly given model = ModelWithDefaultField.construct(with_none_default="bar", with_str_default="baz") assert model.with_none_default == "bar" assert model.with_str_default == "baz" - assert await transform(model, Any, use_async) == {"with_none_default": "bar", "with_str_default": "baz"} + assert cast(Any, await transform(model, Any, use_async)) == {"with_none_default": "bar", "with_str_default": "baz"} class TypedDictIterableUnion(TypedDict): @@ -371,6 +388,15 @@ def my_iter() -> Iterable[Baz8]: } +@parametrize +@pytest.mark.asyncio +async def test_dictionary_items(use_async: bool) -> None: + class DictItems(TypedDict): + foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")] + + assert await transform({"foo": {"foo_baz": "bar"}}, Dict[str, DictItems], use_async) == {"foo": {"fooBaz": "bar"}} + + class TypedDictIterableUnionStr(TypedDict): foo: Annotated[Union[str, Iterable[Baz8]], PropertyInfo(alias="FOO")] @@ -406,3 +432,29 @@ async def test_base64_file_input(use_async: bool) -> None: assert await transform({"foo": io.BytesIO(b"Hello, world!")}, TypedDictBase64Input, use_async) == { "foo": "SGVsbG8sIHdvcmxkIQ==" } # type: ignore[comparison-overlap] + + +@parametrize +@pytest.mark.asyncio +async def test_transform_skipping(use_async: bool) -> None: + # lists of ints are left as-is + data = [1, 2, 3] + assert await transform(data, List[int], use_async) is data + + # iterables of ints are converted to a list + data = iter([1, 2, 3]) + assert await transform(data, Iterable[int], use_async) == [1, 2, 3] + + +@parametrize +@pytest.mark.asyncio +async def test_strips_notgiven(use_async: bool) -> None: + assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} + assert await transform({"foo_bar": not_given}, Foo1, use_async) == {} + + +@parametrize +@pytest.mark.asyncio +async def test_strips_omit(use_async: bool) -> None: + assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} + assert await transform({"foo_bar": omit}, Foo1, use_async) == {} diff --git a/tests/test_utils/test_datetime_parse.py b/tests/test_utils/test_datetime_parse.py new file mode 100644 index 00000000..57c331ff --- /dev/null +++ b/tests/test_utils/test_datetime_parse.py @@ -0,0 +1,110 @@ +""" +Copied from https://github.com/pydantic/pydantic/blob/v1.10.22/tests/test_datetime_parse.py +with modifications so it works without pydantic v1 imports. +""" + +from typing import Type, Union +from datetime import date, datetime, timezone, timedelta + +import pytest + +from orb._utils import parse_date, parse_datetime + + +def create_tz(minutes: int) -> timezone: + return timezone(timedelta(minutes=minutes)) + + +@pytest.mark.parametrize( + "value,result", + [ + # Valid inputs + ("1494012444.883309", date(2017, 5, 5)), + (b"1494012444.883309", date(2017, 5, 5)), + (1_494_012_444.883_309, date(2017, 5, 5)), + ("1494012444", date(2017, 5, 5)), + (1_494_012_444, date(2017, 5, 5)), + (0, date(1970, 1, 1)), + ("2012-04-23", date(2012, 4, 23)), + (b"2012-04-23", date(2012, 4, 23)), + ("2012-4-9", date(2012, 4, 9)), + (date(2012, 4, 9), date(2012, 4, 9)), + (datetime(2012, 4, 9, 12, 15), date(2012, 4, 9)), + # Invalid inputs + ("x20120423", ValueError), + ("2012-04-56", ValueError), + (19_999_999_999, date(2603, 10, 11)), # just before watershed + (20_000_000_001, date(1970, 8, 20)), # just after watershed + (1_549_316_052, date(2019, 2, 4)), # nowish in s + (1_549_316_052_104, date(2019, 2, 4)), # nowish in ms + (1_549_316_052_104_324, date(2019, 2, 4)), # nowish in μs + (1_549_316_052_104_324_096, date(2019, 2, 4)), # nowish in ns + ("infinity", date(9999, 12, 31)), + ("inf", date(9999, 12, 31)), + (float("inf"), date(9999, 12, 31)), + ("infinity ", date(9999, 12, 31)), + (int("1" + "0" * 100), date(9999, 12, 31)), + (1e1000, date(9999, 12, 31)), + ("-infinity", date(1, 1, 1)), + ("-inf", date(1, 1, 1)), + ("nan", ValueError), + ], +) +def test_date_parsing(value: Union[str, bytes, int, float], result: Union[date, Type[Exception]]) -> None: + if type(result) == type and issubclass(result, Exception): # pyright: ignore[reportUnnecessaryIsInstance] + with pytest.raises(result): + parse_date(value) + else: + assert parse_date(value) == result + + +@pytest.mark.parametrize( + "value,result", + [ + # Valid inputs + # values in seconds + ("1494012444.883309", datetime(2017, 5, 5, 19, 27, 24, 883_309, tzinfo=timezone.utc)), + (1_494_012_444.883_309, datetime(2017, 5, 5, 19, 27, 24, 883_309, tzinfo=timezone.utc)), + ("1494012444", datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + (b"1494012444", datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + (1_494_012_444, datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + # values in ms + ("1494012444000.883309", datetime(2017, 5, 5, 19, 27, 24, 883, tzinfo=timezone.utc)), + ("-1494012444000.883309", datetime(1922, 8, 29, 4, 32, 35, 999117, tzinfo=timezone.utc)), + (1_494_012_444_000, datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + ("2012-04-23T09:15:00", datetime(2012, 4, 23, 9, 15)), + ("2012-4-9 4:8:16", datetime(2012, 4, 9, 4, 8, 16)), + ("2012-04-23T09:15:00Z", datetime(2012, 4, 23, 9, 15, 0, 0, timezone.utc)), + ("2012-4-9 4:8:16-0320", datetime(2012, 4, 9, 4, 8, 16, 0, create_tz(-200))), + ("2012-04-23T10:20:30.400+02:30", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(150))), + ("2012-04-23T10:20:30.400+02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(120))), + ("2012-04-23T10:20:30.400-02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(-120))), + (b"2012-04-23T10:20:30.400-02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(-120))), + (datetime(2017, 5, 5), datetime(2017, 5, 5)), + (0, datetime(1970, 1, 1, 0, 0, 0, tzinfo=timezone.utc)), + # Invalid inputs + ("x20120423091500", ValueError), + ("2012-04-56T09:15:90", ValueError), + ("2012-04-23T11:05:00-25:00", ValueError), + (19_999_999_999, datetime(2603, 10, 11, 11, 33, 19, tzinfo=timezone.utc)), # just before watershed + (20_000_000_001, datetime(1970, 8, 20, 11, 33, 20, 1000, tzinfo=timezone.utc)), # just after watershed + (1_549_316_052, datetime(2019, 2, 4, 21, 34, 12, 0, tzinfo=timezone.utc)), # nowish in s + (1_549_316_052_104, datetime(2019, 2, 4, 21, 34, 12, 104_000, tzinfo=timezone.utc)), # nowish in ms + (1_549_316_052_104_324, datetime(2019, 2, 4, 21, 34, 12, 104_324, tzinfo=timezone.utc)), # nowish in μs + (1_549_316_052_104_324_096, datetime(2019, 2, 4, 21, 34, 12, 104_324, tzinfo=timezone.utc)), # nowish in ns + ("infinity", datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("inf", datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("inf ", datetime(9999, 12, 31, 23, 59, 59, 999999)), + (1e50, datetime(9999, 12, 31, 23, 59, 59, 999999)), + (float("inf"), datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("-infinity", datetime(1, 1, 1, 0, 0)), + ("-inf", datetime(1, 1, 1, 0, 0)), + ("nan", ValueError), + ], +) +def test_datetime_parsing(value: Union[str, bytes, int, float], result: Union[datetime, Type[Exception]]) -> None: + if type(result) == type and issubclass(result, Exception): # pyright: ignore[reportUnnecessaryIsInstance] + with pytest.raises(result): + parse_datetime(value) + else: + assert parse_datetime(value) == result diff --git a/tests/test_utils/test_json.py b/tests/test_utils/test_json.py new file mode 100644 index 00000000..fbcbcffb --- /dev/null +++ b/tests/test_utils/test_json.py @@ -0,0 +1,126 @@ +from __future__ import annotations + +import datetime +from typing import Union + +import pydantic + +from orb import _compat +from orb._utils._json import openapi_dumps + + +class TestOpenapiDumps: + def test_basic(self) -> None: + data = {"key": "value", "number": 42} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"key":"value","number":42}' + + def test_datetime_serialization(self) -> None: + dt = datetime.datetime(2023, 1, 1, 12, 0, 0) + data = {"datetime": dt} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"datetime":"2023-01-01T12:00:00"}' + + def test_pydantic_model_serialization(self) -> None: + class User(pydantic.BaseModel): + first_name: str + last_name: str + age: int + + model_instance = User(first_name="John", last_name="Kramer", age=83) + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"first_name":"John","last_name":"Kramer","age":83}}' + + def test_pydantic_model_with_default_values(self) -> None: + class User(pydantic.BaseModel): + name: str + role: str = "user" + active: bool = True + score: int = 0 + + model_instance = User(name="Alice") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Alice"}}' + + def test_pydantic_model_with_default_values_overridden(self) -> None: + class User(pydantic.BaseModel): + name: str + role: str = "user" + active: bool = True + + model_instance = User(name="Bob", role="admin", active=False) + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Bob","role":"admin","active":false}}' + + def test_pydantic_model_with_alias(self) -> None: + class User(pydantic.BaseModel): + first_name: str = pydantic.Field(alias="firstName") + last_name: str = pydantic.Field(alias="lastName") + + model_instance = User(firstName="John", lastName="Doe") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"firstName":"John","lastName":"Doe"}}' + + def test_pydantic_model_with_alias_and_default(self) -> None: + class User(pydantic.BaseModel): + user_name: str = pydantic.Field(alias="userName") + user_role: str = pydantic.Field(default="member", alias="userRole") + is_active: bool = pydantic.Field(default=True, alias="isActive") + + model_instance = User(userName="charlie") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"userName":"charlie"}}' + + model_with_overrides = User(userName="diana", userRole="admin", isActive=False) + data = {"model": model_with_overrides} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"userName":"diana","userRole":"admin","isActive":false}}' + + def test_pydantic_model_with_nested_models_and_defaults(self) -> None: + class Address(pydantic.BaseModel): + street: str + city: str = "Unknown" + + class User(pydantic.BaseModel): + name: str + address: Address + verified: bool = False + + if _compat.PYDANTIC_V1: + # to handle forward references in Pydantic v1 + User.update_forward_refs(**locals()) # type: ignore[reportDeprecated] + + address = Address(street="123 Main St") + user = User(name="Diana", address=address) + data = {"user": user} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"user":{"name":"Diana","address":{"street":"123 Main St"}}}' + + address_with_city = Address(street="456 Oak Ave", city="Boston") + user_verified = User(name="Eve", address=address_with_city, verified=True) + data = {"user": user_verified} + json_bytes = openapi_dumps(data) + assert ( + json_bytes == b'{"user":{"name":"Eve","address":{"street":"456 Oak Ave","city":"Boston"},"verified":true}}' + ) + + def test_pydantic_model_with_optional_fields(self) -> None: + class User(pydantic.BaseModel): + name: str + email: Union[str, None] + phone: Union[str, None] + + model_with_none = User(name="Eve", email=None, phone=None) + data = {"model": model_with_none} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Eve","email":null,"phone":null}}' + + model_with_values = User(name="Frank", email="frank@example.com", phone=None) + data = {"model": model_with_values} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Frank","email":"frank@example.com","phone":null}}' diff --git a/tests/test_utils/test_path.py b/tests/test_utils/test_path.py new file mode 100644 index 00000000..a6b990b5 --- /dev/null +++ b/tests/test_utils/test_path.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +from typing import Any + +import pytest + +from orb._utils._path import path_template + + +@pytest.mark.parametrize( + "template, kwargs, expected", + [ + ("/v1/{id}", dict(id="abc"), "/v1/abc"), + ("/v1/{a}/{b}", dict(a="x", b="y"), "/v1/x/y"), + ("/v1/{a}{b}/path/{c}?val={d}#{e}", dict(a="x", b="y", c="z", d="u", e="v"), "/v1/xy/path/z?val=u#v"), + ("/{w}/{w}", dict(w="echo"), "/echo/echo"), + ("/v1/static", {}, "/v1/static"), + ("", {}, ""), + ("/v1/?q={n}&count=10", dict(n=42), "/v1/?q=42&count=10"), + ("/v1/{v}", dict(v=None), "/v1/null"), + ("/v1/{v}", dict(v=True), "/v1/true"), + ("/v1/{v}", dict(v=False), "/v1/false"), + ("/v1/{v}", dict(v=".hidden"), "/v1/.hidden"), # dot prefix ok + ("/v1/{v}", dict(v="file.txt"), "/v1/file.txt"), # dot in middle ok + ("/v1/{v}", dict(v="..."), "/v1/..."), # triple dot ok + ("/v1/{a}{b}", dict(a=".", b="txt"), "/v1/.txt"), # dot var combining with adjacent to be ok + ("/items?q={v}#{f}", dict(v=".", f=".."), "/items?q=.#.."), # dots in query/fragment are fine + ( + "/v1/{a}?query={b}", + dict(a="../../other/endpoint", b="a&bad=true"), + "/v1/..%2F..%2Fother%2Fendpoint?query=a%26bad%3Dtrue", + ), + ("/v1/{val}", dict(val="a/b/c"), "/v1/a%2Fb%2Fc"), + ("/v1/{val}", dict(val="a/b/c?query=value"), "/v1/a%2Fb%2Fc%3Fquery=value"), + ("/v1/{val}", dict(val="a/b/c?query=value&bad=true"), "/v1/a%2Fb%2Fc%3Fquery=value&bad=true"), + ("/v1/{val}", dict(val="%20"), "/v1/%2520"), # escapes escape sequences in input + # Query: slash and ? are safe, # is not + ("/items?q={v}", dict(v="a/b"), "/items?q=a/b"), + ("/items?q={v}", dict(v="a?b"), "/items?q=a?b"), + ("/items?q={v}", dict(v="a#b"), "/items?q=a%23b"), + ("/items?q={v}", dict(v="a b"), "/items?q=a%20b"), + # Fragment: slash and ? are safe + ("/docs#{v}", dict(v="a/b"), "/docs#a/b"), + ("/docs#{v}", dict(v="a?b"), "/docs#a?b"), + # Path: slash, ? and # are all encoded + ("/v1/{v}", dict(v="a/b"), "/v1/a%2Fb"), + ("/v1/{v}", dict(v="a?b"), "/v1/a%3Fb"), + ("/v1/{v}", dict(v="a#b"), "/v1/a%23b"), + # same var encoded differently by component + ( + "/v1/{v}?q={v}#{v}", + dict(v="a/b?c#d"), + "/v1/a%2Fb%3Fc%23d?q=a/b?c%23d#a/b?c%23d", + ), + ("/v1/{val}", dict(val="x?admin=true"), "/v1/x%3Fadmin=true"), # query injection + ("/v1/{val}", dict(val="x#admin"), "/v1/x%23admin"), # fragment injection + ], +) +def test_interpolation(template: str, kwargs: dict[str, Any], expected: str) -> None: + assert path_template(template, **kwargs) == expected + + +def test_missing_kwarg_raises_key_error() -> None: + with pytest.raises(KeyError, match="org_id"): + path_template("/v1/{org_id}") + + +@pytest.mark.parametrize( + "template, kwargs", + [ + ("{a}/path", dict(a=".")), + ("{a}/path", dict(a="..")), + ("/v1/{a}", dict(a=".")), + ("/v1/{a}", dict(a="..")), + ("/v1/{a}/path", dict(a=".")), + ("/v1/{a}/path", dict(a="..")), + ("/v1/{a}{b}", dict(a=".", b=".")), # adjacent vars → ".." + ("/v1/{a}.", dict(a=".")), # var + static → ".." + ("/v1/{a}{b}", dict(a="", b=".")), # empty + dot → "." + ("/v1/%2e/{x}", dict(x="ok")), # encoded dot in static text + ("/v1/%2e./{x}", dict(x="ok")), # mixed encoded ".." in static + ("/v1/.%2E/{x}", dict(x="ok")), # mixed encoded ".." in static + ("/v1/{v}?q=1", dict(v="..")), + ("/v1/{v}#frag", dict(v="..")), + ], +) +def test_dot_segment_rejected(template: str, kwargs: dict[str, Any]) -> None: + with pytest.raises(ValueError, match="dot-segment"): + path_template(template, **kwargs) diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py index 2aafc1f3..8b8e20c9 100644 --- a/tests/test_utils/test_proxy.py +++ b/tests/test_utils/test_proxy.py @@ -21,3 +21,14 @@ def test_recursive_proxy() -> None: assert dir(proxy) == [] assert type(proxy).__name__ == "RecursiveLazyProxy" assert type(operator.attrgetter("name.foo.bar.baz")(proxy)).__name__ == "RecursiveLazyProxy" + + +def test_isinstance_does_not_error() -> None: + class AlwaysErrorProxy(LazyProxy[Any]): + @override + def __load__(self) -> Any: + raise RuntimeError("Mocking missing dependency") + + proxy = AlwaysErrorProxy() + assert not isinstance(proxy, dict) + assert isinstance(proxy, LazyProxy) diff --git a/tests/test_utils/test_typing.py b/tests/test_utils/test_typing.py index c3e42410..3826b105 100644 --- a/tests/test_utils/test_typing.py +++ b/tests/test_utils/test_typing.py @@ -9,24 +9,19 @@ _T3 = TypeVar("_T3") -class BaseGeneric(Generic[_T]): - ... +class BaseGeneric(Generic[_T]): ... -class SubclassGeneric(BaseGeneric[_T]): - ... +class SubclassGeneric(BaseGeneric[_T]): ... -class BaseGenericMultipleTypeArgs(Generic[_T, _T2, _T3]): - ... +class BaseGenericMultipleTypeArgs(Generic[_T, _T2, _T3]): ... -class SubclassGenericMultipleTypeArgs(BaseGenericMultipleTypeArgs[_T, _T2, _T3]): - ... +class SubclassGenericMultipleTypeArgs(BaseGenericMultipleTypeArgs[_T, _T2, _T3]): ... -class SubclassDifferentOrderGenericMultipleTypeArgs(BaseGenericMultipleTypeArgs[_T2, _T, _T3]): - ... +class SubclassDifferentOrderGenericMultipleTypeArgs(BaseGenericMultipleTypeArgs[_T2, _T, _T3]): ... def test_extract_type_var() -> None: diff --git a/tests/utils.py b/tests/utils.py index 7ce2711c..db0cb1be 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -4,20 +4,22 @@ import inspect import traceback import contextlib -from typing import Any, TypeVar, Iterator, cast +from typing import Any, TypeVar, Iterator, Sequence, cast from datetime import date, datetime from typing_extensions import Literal, get_args, get_origin, assert_type -from orb._types import NoneType +from orb._types import Omit, NoneType from orb._utils import ( is_dict, is_list, is_list_type, is_union_type, extract_type_arg, + is_sequence_type, is_annotated_type, + is_type_alias_type, ) -from orb._compat import PYDANTIC_V2, field_outer_type, get_model_fields +from orb._compat import PYDANTIC_V1, field_outer_type, get_model_fields from orb._models import BaseModel BaseModelT = TypeVar("BaseModelT", bound=BaseModel) @@ -26,12 +28,12 @@ def assert_matches_model(model: type[BaseModelT], value: BaseModelT, *, path: list[str]) -> bool: for name, field in get_model_fields(model).items(): field_value = getattr(value, name) - if PYDANTIC_V2: - allow_none = False - else: + if PYDANTIC_V1: # in v1 nullability was structured differently # https://docs.pydantic.dev/2.0/migration/#required-optional-and-nullable-fields allow_none = getattr(field, "allow_none", False) + else: + allow_none = False assert_matches_type( field_outer_type(field), @@ -51,6 +53,9 @@ def assert_matches_type( path: list[str], allow_none: bool = False, ) -> None: + if is_type_alias_type(type_): + type_ = type_.__value__ + # unwrap `Annotated[T, ...]` -> `T` if is_annotated_type(type_): type_ = extract_type_arg(type_, 0) @@ -67,6 +72,13 @@ def assert_matches_type( if is_list_type(type_): return _assert_list_type(type_, value) + if is_sequence_type(type_): + assert isinstance(value, Sequence) + inner_type = get_args(type_)[0] + for entry in value: # type: ignore + assert_type(inner_type, entry) # type: ignore + return + if origin == str: assert isinstance(value, str) elif origin == int: @@ -97,7 +109,22 @@ def assert_matches_type( assert_matches_type(key_type, key, path=[*path, ""]) assert_matches_type(items_type, item, path=[*path, ""]) elif is_union_type(type_): - for i, variant in enumerate(get_args(type_)): + variants = get_args(type_) + + try: + none_index = variants.index(type(None)) + except ValueError: + pass + else: + # special case Optional[T] for better error messages + if len(variants) == 2: + if value is None: + # valid + return + + return assert_matches_type(type_=variants[not none_index], value=value, path=path) + + for i, variant in enumerate(variants): try: assert_matches_type(variant, value, path=[*path, f"variant {i}"]) return @@ -124,11 +151,15 @@ def _assert_list_type(type_: type[object], value: object) -> None: @contextlib.contextmanager -def update_env(**new_env: str) -> Iterator[None]: +def update_env(**new_env: str | Omit) -> Iterator[None]: old = os.environ.copy() try: - os.environ.update(new_env) + for name, value in new_env.items(): + if isinstance(value, Omit): + os.environ.pop(name, None) + else: + os.environ[name] = value yield None finally: