From e95eb1d93a4990d3fe2d722abf05b4bfa558c745 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 6 Jan 2025 23:13:35 +0000
Subject: [PATCH 01/21] chore(internal): version bump (#469)
From 441731c3d5efe8a38ec0fc5243327bfa928fe651 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 20 Dec 2024 01:17:42 +0000
Subject: [PATCH 02/21] codegen metadata
---
.stats.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.stats.yml b/.stats.yml
index fcff3ba6..3147fc5b 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
configured_endpoints: 97
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-02151f7654870aee7820ee1c04659a469e6b67ac4977116334512c6b6e6a2016.yml
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-d0a97f690d07742fea0d6c9b9b0d9dae5e8490eb03a7f3da27989fdf53d3e45d.yml
From d23ec0e08cc5e8bd681a8c7947778a8445b81f78 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 23 Dec 2024 23:40:28 +0000
Subject: [PATCH 03/21] feat(api): api update (#471)
---
.stats.yml | 2 +-
.../resources/customers/credits/credits.py | 24 +++++++++++++++----
.../credit_list_by_external_id_params.py | 5 +++-
src/orb/types/customers/credit_list_params.py | 5 +++-
4 files changed, 29 insertions(+), 7 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 3147fc5b..09794c42 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
configured_endpoints: 97
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-d0a97f690d07742fea0d6c9b9b0d9dae5e8490eb03a7f3da27989fdf53d3e45d.yml
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-77f4e8cf0fc3b3f18c894408f322af7988ae90606235fe5058442409142a33e1.yml
diff --git a/src/orb/resources/customers/credits/credits.py b/src/orb/resources/customers/credits/credits.py
index 2fd36621..7b27df42 100644
--- a/src/orb/resources/customers/credits/credits.py
+++ b/src/orb/resources/customers/credits/credits.py
@@ -83,6 +83,9 @@ def list(
"""
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.
@@ -92,7 +95,8 @@ def list(
cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned
from the initial request.
- include_all_blocks: Include all blocks, not just active ones.
+ 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.
@@ -145,6 +149,9 @@ def list_by_external_id(
"""
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.
@@ -154,7 +161,8 @@ def list_by_external_id(
cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned
from the initial request.
- include_all_blocks: Include all blocks, not just active ones.
+ 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.
@@ -238,6 +246,9 @@ def list(
"""
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.
@@ -247,7 +258,8 @@ def list(
cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned
from the initial request.
- include_all_blocks: Include all blocks, not just active ones.
+ 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.
@@ -300,6 +312,9 @@ def list_by_external_id(
"""
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.
@@ -309,7 +324,8 @@ def list_by_external_id(
cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned
from the initial request.
- include_all_blocks: Include all blocks, not just active ones.
+ 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.
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 b192dc5c..4074c82e 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
@@ -20,7 +20,10 @@ class CreditListByExternalIDParams(TypedDict, total=False):
"""
include_all_blocks: bool
- """Include all blocks, not just active ones."""
+ """
+ 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_params.py b/src/orb/types/customers/credit_list_params.py
index 9e8d7ba7..cb3f767b 100644
--- a/src/orb/types/customers/credit_list_params.py
+++ b/src/orb/types/customers/credit_list_params.py
@@ -20,7 +20,10 @@ class CreditListParams(TypedDict, total=False):
"""
include_all_blocks: bool
- """Include all blocks, not just active ones."""
+ """
+ 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."""
From 0a2235016cfba90da5f68e950579d0720bd40045 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 24 Dec 2024 10:11:21 +0000
Subject: [PATCH 04/21] feat(api): api update (#472)
---
.stats.yml | 4 +-
api.md | 20 +
src/orb/_client.py | 17 +
src/orb/resources/__init__.py | 14 +
.../dimensional_price_groups/__init__.py | 33 ++
.../dimensional_price_groups.py | 463 ++++++++++++++++++
.../external_dimensional_price_group_id.py | 163 ++++++
src/orb/types/__init__.py | 6 +
src/orb/types/dimensional_price_group.py | 35 ++
.../dimensional_price_group_create_params.py | 26 +
.../dimensional_price_group_list_params.py | 20 +
.../dimensional_price_groups/__init__.py | 5 +
.../dimensional_price_groups.py | 15 +
.../dimensional_price_groups/__init__.py | 1 +
...est_external_dimensional_price_group_id.py | 108 ++++
.../test_dimensional_price_groups.py | 265 ++++++++++
16 files changed, 1193 insertions(+), 2 deletions(-)
create mode 100644 src/orb/resources/dimensional_price_groups/__init__.py
create mode 100644 src/orb/resources/dimensional_price_groups/dimensional_price_groups.py
create mode 100644 src/orb/resources/dimensional_price_groups/external_dimensional_price_group_id.py
create mode 100644 src/orb/types/dimensional_price_group.py
create mode 100644 src/orb/types/dimensional_price_group_create_params.py
create mode 100644 src/orb/types/dimensional_price_group_list_params.py
create mode 100644 src/orb/types/dimensional_price_groups/__init__.py
create mode 100644 src/orb/types/dimensional_price_groups/dimensional_price_groups.py
create mode 100644 tests/api_resources/dimensional_price_groups/__init__.py
create mode 100644 tests/api_resources/dimensional_price_groups/test_external_dimensional_price_group_id.py
create mode 100644 tests/api_resources/test_dimensional_price_groups.py
diff --git a/.stats.yml b/.stats.yml
index 09794c42..c963fb86 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
-configured_endpoints: 97
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-77f4e8cf0fc3b3f18c894408f322af7988ae90606235fe5058442409142a33e1.yml
+configured_endpoints: 101
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-726c25fdf0fdd4b7c5a9c36d30e33990d2a4b63c4260be340400f8ded23b578f.yml
diff --git a/api.md b/api.md
index f9a7248e..c6fdb8fa 100644
--- a/api.md
+++ b/api.md
@@ -387,3 +387,23 @@ Methods:
- 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
+
+# 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.list(\*\*params) -> SyncPage[DimensionalPriceGroup]
+
+## ExternalDimensionalPriceGroupID
+
+Methods:
+
+- client.dimensional_price_groups.external_dimensional_price_group_id.retrieve(external_dimensional_price_group_id) -> DimensionalPriceGroup
diff --git a/src/orb/_client.py b/src/orb/_client.py
index 4a341ccc..2a1f1497 100644
--- a/src/orb/_client.py
+++ b/src/orb/_client.py
@@ -48,6 +48,7 @@
from .resources.prices import prices
from .resources.coupons import coupons
from .resources.customers import customers
+from .resources.dimensional_price_groups import dimensional_price_groups
__all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Orb", "AsyncOrb", "Client", "AsyncClient"]
@@ -67,6 +68,7 @@ class Orb(SyncAPIClient):
subscriptions: subscriptions.Subscriptions
webhooks: webhooks.Webhooks
alerts: alerts.Alerts
+ dimensional_price_groups: dimensional_price_groups.DimensionalPriceGroups
with_raw_response: OrbWithRawResponse
with_streaming_response: OrbWithStreamedResponse
@@ -148,6 +150,7 @@ def __init__(
self.subscriptions = subscriptions.Subscriptions(self)
self.webhooks = webhooks.Webhooks(self)
self.alerts = alerts.Alerts(self)
+ self.dimensional_price_groups = dimensional_price_groups.DimensionalPriceGroups(self)
self.with_raw_response = OrbWithRawResponse(self)
self.with_streaming_response = OrbWithStreamedResponse(self)
@@ -321,6 +324,7 @@ class AsyncOrb(AsyncAPIClient):
subscriptions: subscriptions.AsyncSubscriptions
webhooks: webhooks.AsyncWebhooks
alerts: alerts.AsyncAlerts
+ dimensional_price_groups: dimensional_price_groups.AsyncDimensionalPriceGroups
with_raw_response: AsyncOrbWithRawResponse
with_streaming_response: AsyncOrbWithStreamedResponse
@@ -402,6 +406,7 @@ def __init__(
self.subscriptions = subscriptions.AsyncSubscriptions(self)
self.webhooks = webhooks.AsyncWebhooks(self)
self.alerts = alerts.AsyncAlerts(self)
+ self.dimensional_price_groups = dimensional_price_groups.AsyncDimensionalPriceGroups(self)
self.with_raw_response = AsyncOrbWithRawResponse(self)
self.with_streaming_response = AsyncOrbWithStreamedResponse(self)
@@ -575,6 +580,9 @@ def __init__(self, client: Orb) -> None:
self.prices = prices.PricesWithRawResponse(client.prices)
self.subscriptions = subscriptions.SubscriptionsWithRawResponse(client.subscriptions)
self.alerts = alerts.AlertsWithRawResponse(client.alerts)
+ self.dimensional_price_groups = dimensional_price_groups.DimensionalPriceGroupsWithRawResponse(
+ client.dimensional_price_groups
+ )
class AsyncOrbWithRawResponse:
@@ -592,6 +600,9 @@ def __init__(self, client: AsyncOrb) -> None:
self.prices = prices.AsyncPricesWithRawResponse(client.prices)
self.subscriptions = subscriptions.AsyncSubscriptionsWithRawResponse(client.subscriptions)
self.alerts = alerts.AsyncAlertsWithRawResponse(client.alerts)
+ self.dimensional_price_groups = dimensional_price_groups.AsyncDimensionalPriceGroupsWithRawResponse(
+ client.dimensional_price_groups
+ )
class OrbWithStreamedResponse:
@@ -609,6 +620,9 @@ def __init__(self, client: Orb) -> None:
self.prices = prices.PricesWithStreamingResponse(client.prices)
self.subscriptions = subscriptions.SubscriptionsWithStreamingResponse(client.subscriptions)
self.alerts = alerts.AlertsWithStreamingResponse(client.alerts)
+ self.dimensional_price_groups = dimensional_price_groups.DimensionalPriceGroupsWithStreamingResponse(
+ client.dimensional_price_groups
+ )
class AsyncOrbWithStreamedResponse:
@@ -628,6 +642,9 @@ def __init__(self, client: AsyncOrb) -> None:
self.prices = prices.AsyncPricesWithStreamingResponse(client.prices)
self.subscriptions = subscriptions.AsyncSubscriptionsWithStreamingResponse(client.subscriptions)
self.alerts = alerts.AsyncAlertsWithStreamingResponse(client.alerts)
+ self.dimensional_price_groups = dimensional_price_groups.AsyncDimensionalPriceGroupsWithStreamingResponse(
+ client.dimensional_price_groups
+ )
Client = Orb
diff --git a/src/orb/resources/__init__.py b/src/orb/resources/__init__.py
index f5515f6c..ccb3f489 100644
--- a/src/orb/resources/__init__.py
+++ b/src/orb/resources/__init__.py
@@ -108,6 +108,14 @@
InvoiceLineItemsWithStreamingResponse,
AsyncInvoiceLineItemsWithStreamingResponse,
)
+from .dimensional_price_groups import (
+ DimensionalPriceGroups,
+ AsyncDimensionalPriceGroups,
+ DimensionalPriceGroupsWithRawResponse,
+ AsyncDimensionalPriceGroupsWithRawResponse,
+ DimensionalPriceGroupsWithStreamingResponse,
+ AsyncDimensionalPriceGroupsWithStreamingResponse,
+)
__all__ = [
"TopLevel",
@@ -190,4 +198,10 @@
"AsyncAlertsWithRawResponse",
"AlertsWithStreamingResponse",
"AsyncAlertsWithStreamingResponse",
+ "DimensionalPriceGroups",
+ "AsyncDimensionalPriceGroups",
+ "DimensionalPriceGroupsWithRawResponse",
+ "AsyncDimensionalPriceGroupsWithRawResponse",
+ "DimensionalPriceGroupsWithStreamingResponse",
+ "AsyncDimensionalPriceGroupsWithStreamingResponse",
]
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..8d220f77
--- /dev/null
+++ b/src/orb/resources/dimensional_price_groups/dimensional_price_groups.py
@@ -0,0 +1,463 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, List, Optional
+
+import httpx
+
+from ... import _legacy_response
+from ...types import dimensional_price_group_list_params, dimensional_price_group_create_params
+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 ...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
+ 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: List[str],
+ name: str,
+ external_dimensional_price_group_id: Optional[str] | NotGiven = NOT_GIVEN,
+ metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ idempotency_key: str | None = None,
+ ) -> 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 parition 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(
+ f"/dimensional_price_groups/{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 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[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
+ 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: List[str],
+ name: str,
+ external_dimensional_price_group_id: Optional[str] | NotGiven = NOT_GIVEN,
+ metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ idempotency_key: str | None = None,
+ ) -> 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 parition 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(
+ f"/dimensional_price_groups/{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 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,
+ ) -> 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.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.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.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.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..f137f4d3
--- /dev/null
+++ b/src/orb/resources/dimensional_price_groups/external_dimensional_price_group_id.py
@@ -0,0 +1,163 @@
+# 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 NOT_GIVEN, Body, Query, Headers, NotGiven
+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
+
+__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
+ 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(
+ f"/dimensional_price_groups/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,
+ )
+
+
+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
+ 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(
+ f"/dimensional_price_groups/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,
+ )
+
+
+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,
+ )
+
+
+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,
+ )
+
+
+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,
+ )
+
+
+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,
+ )
diff --git a/src/orb/types/__init__.py b/src/orb/types/__init__.py
index 18c8b027..c7eb0152 100644
--- a/src/orb/types/__init__.py
+++ b/src/orb/types/__init__.py
@@ -57,8 +57,10 @@
from .customer_create_params import CustomerCreateParams as CustomerCreateParams
from .customer_update_params import CustomerUpdateParams as CustomerUpdateParams
from .credit_note_list_params import CreditNoteListParams as CreditNoteListParams
+from .dimensional_price_group import DimensionalPriceGroup as DimensionalPriceGroup
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 .subscription_list_params import SubscriptionListParams as SubscriptionListParams
@@ -80,11 +82,15 @@
from .subscription_trigger_phase_params import SubscriptionTriggerPhaseParams as SubscriptionTriggerPhaseParams
from .subscription_fetch_schedule_params import SubscriptionFetchScheduleParams as SubscriptionFetchScheduleParams
from .subscription_update_trial_response import SubscriptionUpdateTrialResponse as SubscriptionUpdateTrialResponse
+from .dimensional_price_group_list_params import DimensionalPriceGroupListParams as DimensionalPriceGroupListParams
from .subscription_price_intervals_params import SubscriptionPriceIntervalsParams as SubscriptionPriceIntervalsParams
from .subscription_trigger_phase_response import SubscriptionTriggerPhaseResponse as SubscriptionTriggerPhaseResponse
from .alert_create_for_subscription_params import AlertCreateForSubscriptionParams as AlertCreateForSubscriptionParams
from .subscription_fetch_schedule_response import SubscriptionFetchScheduleResponse as SubscriptionFetchScheduleResponse
from .customer_update_by_external_id_params import CustomerUpdateByExternalIDParams as CustomerUpdateByExternalIDParams
+from .dimensional_price_group_create_params import (
+ DimensionalPriceGroupCreateParams as DimensionalPriceGroupCreateParams,
+)
from .subscription_price_intervals_response import (
SubscriptionPriceIntervalsResponse as SubscriptionPriceIntervalsResponse,
)
diff --git a/src/orb/types/dimensional_price_group.py b/src/orb/types/dimensional_price_group.py
new file mode 100644
index 00000000..da103128
--- /dev/null
+++ b/src/orb/types/dimensional_price_group.py
@@ -0,0 +1,35 @@
+# 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):
+ 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..36c07bf1
--- /dev/null
+++ b/src/orb/types/dimensional_price_group_create_params.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, List, Optional
+from typing_extensions import Required, TypedDict
+
+__all__ = ["DimensionalPriceGroupCreateParams"]
+
+
+class DimensionalPriceGroupCreateParams(TypedDict, total=False):
+ billable_metric_id: Required[str]
+
+ dimensions: Required[List[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_groups/__init__.py b/src/orb/types/dimensional_price_groups/__init__.py
new file mode 100644
index 00000000..6237c9ac
--- /dev/null
+++ b/src/orb/types/dimensional_price_groups/__init__.py
@@ -0,0 +1,5 @@
+# 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
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/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..d4fd8c5a
--- /dev/null
+++ b/tests/api_resources/dimensional_price_groups/test_external_dimensional_price_group_id.py
@@ -0,0 +1,108 @@
+# 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(
+ "",
+ )
+
+
+class TestAsyncExternalDimensionalPriceGroupID:
+ parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @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(
+ "",
+ )
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..d371b7c5
--- /dev/null
+++ b/tests/api_resources/test_dimensional_price_groups.py
@@ -0,0 +1,265 @@
+# 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_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], indirect=True, ids=["loose", "strict"])
+
+ @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_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
From 9406c9ab61d6969699bbb028b3d953cba02b0706 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 25 Dec 2024 20:37:36 +0000
Subject: [PATCH 05/21] codegen metadata
---
.stats.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.stats.yml b/.stats.yml
index c963fb86..0b824ed2 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
configured_endpoints: 101
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-726c25fdf0fdd4b7c5a9c36d30e33990d2a4b63c4260be340400f8ded23b578f.yml
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-c5fe55b056b10d6581c877beb0639a8f0a623e52fd9778e56fab8a86439bd31b.yml
From c24985f1ff9e87de455a4b862045701f6c646bab Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 1 Jan 2025 19:36:14 +0000
Subject: [PATCH 06/21] chore(internal): codegen related update (#473)
---
LICENSE | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/LICENSE b/LICENSE
index 782200ee..00b1f9c8 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 2025 Orb
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
From d2fb2aa50c27160a8fd386aec812e8f3ace527fe Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 3 Jan 2025 19:47:41 +0000
Subject: [PATCH 07/21] feat(api): api update (#474)
---
.stats.yml | 2 +-
src/orb/resources/events/backfills.py | 12 +++++---
src/orb/resources/events/events.py | 8 +++---
src/orb/types/alert.py | 41 +++++++++++++++++++++++----
4 files changed, 48 insertions(+), 15 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 0b824ed2..7dd05a09 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
configured_endpoints: 101
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-c5fe55b056b10d6581c877beb0639a8f0a623e52fd9778e56fab8a86439bd31b.yml
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-52bd3046e73f201c4d08edfa92756791c015be907691a7893f8e7782cc2aea6f.yml
diff --git a/src/orb/resources/events/backfills.py b/src/orb/resources/events/backfills.py
index 112f7807..a7894d16 100644
--- a/src/orb/resources/events/backfills.py
+++ b/src/orb/resources/events/backfills.py
@@ -97,8 +97,10 @@ def create(
only affect events for that customer. If neither is specified, the backfill will
affect all customers.
- When `replace_existing_events` is `true`, the field `filter` can be optionally
- added which enables filtering using
+ 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 `filter` can be optionally added which enables filtering
+ using
[computed properties](../guides/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.
@@ -407,8 +409,10 @@ async def create(
only affect events for that customer. If neither is specified, the backfill will
affect all customers.
- When `replace_existing_events` is `true`, the field `filter` can be optionally
- added which enables filtering using
+ 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 `filter` can be optionally added which enables filtering
+ using
[computed properties](../guides/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.
diff --git a/src/orb/resources/events/events.py b/src/orb/resources/events/events.py
index 3d4efed8..31f731ad 100644
--- a/src/orb/resources/events/events.py
+++ b/src/orb/resources/events/events.py
@@ -211,8 +211,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
@@ -760,8 +760,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
diff --git a/src/orb/types/alert.py b/src/orb/types/alert.py
index 7a7dd4b2..0ef04360 100644
--- a/src/orb/types/alert.py
+++ b/src/orb/types/alert.py
@@ -1,12 +1,41 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Dict, List, Optional
+from typing import List, Optional
from datetime import datetime
from typing_extensions import Literal
from .._models import BaseModel
-__all__ = ["Alert", "Threshold"]
+__all__ = ["Alert", "Customer", "Metric", "Plan", "Subscription", "Threshold"]
+
+
+class Customer(BaseModel):
+ id: str
+
+ external_customer_id: Optional[str] = None
+
+
+class Metric(BaseModel):
+ id: str
+
+
+class Plan(BaseModel):
+ 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 Subscription(BaseModel):
+ id: str
class Threshold(BaseModel):
@@ -28,19 +57,19 @@ class Alert(BaseModel):
currency: Optional[str] = None
"""The name of the currency the credit balance or invoice cost is denominated in."""
- customer: Optional[Dict[str, Optional[str]]] = None
+ customer: Optional[Customer] = None
"""The customer the alert applies to."""
enabled: bool
"""Whether the alert is enabled or disabled."""
- metric: Optional[Dict[str, Optional[str]]] = None
+ metric: Optional[Metric] = None
"""The metric the alert applies to."""
- plan: Optional[Dict[str, Optional[str]]] = None
+ plan: Optional[Plan] = None
"""The plan the alert applies to."""
- subscription: Optional[Dict[str, Optional[str]]] = None
+ subscription: Optional[Subscription] = None
"""The subscription the alert applies to."""
thresholds: Optional[List[Threshold]] = None
From f684ed42a5452933f4fe5a495b309a74267e4728 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 6 Jan 2025 15:46:06 +0000
Subject: [PATCH 08/21] chore(client): simplify `Optional[object]` to just
`object` (#475)
---
src/orb/types/invoice.py | 2 +-
src/orb/types/invoice_fetch_upcoming_response.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/orb/types/invoice.py b/src/orb/types/invoice.py
index 964e0f7d..1daa1271 100644
--- a/src/orb/types/invoice.py
+++ b/src/orb/types/invoice.py
@@ -918,7 +918,7 @@ class Invoice(BaseModel):
| Vietnam | `vn_tin` | Vietnamese Tax ID Number |
"""
- discount: Optional[object] = None
+ discount: object
"""This field is deprecated in favor of `discounts`.
If a `discounts` list is provided, the first discount in the list will be
diff --git a/src/orb/types/invoice_fetch_upcoming_response.py b/src/orb/types/invoice_fetch_upcoming_response.py
index 8ec2e987..3a716af2 100644
--- a/src/orb/types/invoice_fetch_upcoming_response.py
+++ b/src/orb/types/invoice_fetch_upcoming_response.py
@@ -918,7 +918,7 @@ class InvoiceFetchUpcomingResponse(BaseModel):
| Vietnam | `vn_tin` | Vietnamese Tax ID Number |
"""
- discount: Optional[object] = None
+ discount: object
"""This field is deprecated in favor of `discounts`.
If a `discounts` list is provided, the first discount in the list will be
From cafafe4cfdfd12d1bbad5d1fce0ad0b992741993 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 6 Jan 2025 17:14:03 +0000
Subject: [PATCH 09/21] chore: add missing isclass check (#476)
---
src/orb/_models.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/orb/_models.py b/src/orb/_models.py
index 7a547ce5..d56ea1d9 100644
--- a/src/orb/_models.py
+++ b/src/orb/_models.py
@@ -488,7 +488,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]
From 59c3a8bdfa3b18311e956511afd31d211c6f320d Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 6 Jan 2025 17:56:43 +0000
Subject: [PATCH 10/21] feat(api): api update (#477)
---
.stats.yml | 2 +-
src/orb/types/invoice.py | 7 +++++--
src/orb/types/invoice_fetch_upcoming_response.py | 7 +++++--
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 7dd05a09..c4326132 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
configured_endpoints: 101
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-52bd3046e73f201c4d08edfa92756791c015be907691a7893f8e7782cc2aea6f.yml
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-b6d60f8edbdc94e65f06b0b002cc8e1f27aceccc67917bea849425701ba82fb8.yml
diff --git a/src/orb/types/invoice.py b/src/orb/types/invoice.py
index 1daa1271..9799e405 100644
--- a/src/orb/types/invoice.py
+++ b/src/orb/types/invoice.py
@@ -927,8 +927,11 @@ class Invoice(BaseModel):
discounts: List[InvoiceLevelDiscount]
- due_date: datetime
- """When the invoice payment is due."""
+ 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
"""
diff --git a/src/orb/types/invoice_fetch_upcoming_response.py b/src/orb/types/invoice_fetch_upcoming_response.py
index 3a716af2..5b7f7d2c 100644
--- a/src/orb/types/invoice_fetch_upcoming_response.py
+++ b/src/orb/types/invoice_fetch_upcoming_response.py
@@ -927,8 +927,11 @@ class InvoiceFetchUpcomingResponse(BaseModel):
discounts: List[InvoiceLevelDiscount]
- due_date: datetime
- """When the invoice payment is due."""
+ 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
"""
From 4036ecaf1d14f3c235c11ce1551490a86fab8066 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 6 Jan 2025 20:18:01 +0000
Subject: [PATCH 11/21] feat(api): api update (#478)
---
.stats.yml | 2 +-
src/orb/types/invoice.py | 7 ++-----
src/orb/types/invoice_fetch_upcoming_response.py | 7 ++-----
3 files changed, 5 insertions(+), 11 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index c4326132..7dd05a09 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
configured_endpoints: 101
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-b6d60f8edbdc94e65f06b0b002cc8e1f27aceccc67917bea849425701ba82fb8.yml
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-52bd3046e73f201c4d08edfa92756791c015be907691a7893f8e7782cc2aea6f.yml
diff --git a/src/orb/types/invoice.py b/src/orb/types/invoice.py
index 9799e405..1daa1271 100644
--- a/src/orb/types/invoice.py
+++ b/src/orb/types/invoice.py
@@ -927,11 +927,8 @@ class Invoice(BaseModel):
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.
- """
+ due_date: datetime
+ """When the invoice payment is due."""
eligible_to_issue_at: Optional[datetime] = None
"""
diff --git a/src/orb/types/invoice_fetch_upcoming_response.py b/src/orb/types/invoice_fetch_upcoming_response.py
index 5b7f7d2c..3a716af2 100644
--- a/src/orb/types/invoice_fetch_upcoming_response.py
+++ b/src/orb/types/invoice_fetch_upcoming_response.py
@@ -927,11 +927,8 @@ class InvoiceFetchUpcomingResponse(BaseModel):
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.
- """
+ due_date: datetime
+ """When the invoice payment is due."""
eligible_to_issue_at: Optional[datetime] = None
"""
From 6b04deaf0406eb2130ca9f159d42f84bd5ecac4a Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 7 Jan 2025 09:34:37 +0000
Subject: [PATCH 12/21] chore(internal): bump httpx dependency (#480)
---
pyproject.toml | 2 +-
requirements-dev.lock | 5 ++---
requirements.lock | 3 +--
3 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 5e98c63e..6e3ae75c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -54,7 +54,7 @@ dev-dependencies = [
"dirty-equals>=0.6.0",
"importlib-metadata>=6.7.0",
"rich>=13.7.1",
- "nest_asyncio==1.6.0"
+ "nest_asyncio==1.6.0",
]
[tool.rye.scripts]
diff --git a/requirements-dev.lock b/requirements-dev.lock
index a9f3cea1..29b7f1c5 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -35,7 +35,7 @@ h11==0.14.0
# via httpcore
httpcore==1.0.2
# via httpx
-httpx==0.25.2
+httpx==0.28.1
# via orb-billing
# via respx
idna==3.4
@@ -76,7 +76,7 @@ python-dateutil==2.8.2
# via time-machine
pytz==2023.3.post1
# via dirty-equals
-respx==0.20.2
+respx==0.22.0
rich==13.7.1
ruff==0.6.9
setuptools==68.2.2
@@ -85,7 +85,6 @@ six==1.16.0
# via python-dateutil
sniffio==1.3.0
# via anyio
- # via httpx
# via orb-billing
time-machine==2.9.0
tomli==2.0.2
diff --git a/requirements.lock b/requirements.lock
index 844a8552..dcfb84e9 100644
--- a/requirements.lock
+++ b/requirements.lock
@@ -25,7 +25,7 @@ h11==0.14.0
# via httpcore
httpcore==1.0.2
# via httpx
-httpx==0.25.2
+httpx==0.28.1
# via orb-billing
idna==3.4
# via anyio
@@ -36,7 +36,6 @@ pydantic-core==2.27.1
# via pydantic
sniffio==1.3.0
# via anyio
- # via httpx
# via orb-billing
typing-extensions==4.12.2
# via anyio
From c14225cd09e514dea91586874e851cf1933b9af5 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 7 Jan 2025 19:58:55 +0000
Subject: [PATCH 13/21] fix(client): only call .close() when needed (#481)
---
src/orb/_base_client.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/orb/_base_client.py b/src/orb/_base_client.py
index 7a91b0d5..8c04d929 100644
--- a/src/orb/_base_client.py
+++ b/src/orb/_base_client.py
@@ -768,6 +768,9 @@ def __init__(self, **kwargs: Any) -> None:
class SyncHttpxClientWrapper(DefaultHttpxClient):
def __del__(self) -> None:
+ if self.is_closed:
+ return
+
try:
self.close()
except Exception:
@@ -1349,6 +1352,9 @@ def __init__(self, **kwargs: Any) -> None:
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())
From b8a2ce60542927b91329a10dd2d39efac96d6d9b Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 8 Jan 2025 20:57:24 +0000
Subject: [PATCH 14/21] docs: fix typos (#482)
---
README.md | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 89850273..20c1dbb3 100644
--- a/README.md
+++ b/README.md
@@ -217,7 +217,7 @@ except orb.APIStatusError as e:
print(e.response)
```
-Error codes are as followed:
+Error codes are as follows:
| Status Code | Error Type |
| ----------- | -------------------------- |
@@ -328,7 +328,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 [`LegagcyAPIResponse`](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
@@ -367,8 +367,7 @@ If you need to access undocumented endpoints, params, or response properties, th
#### 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
From 569ad308f81bc99620d2d08b3afc4ea95f0fe8d5 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 8 Jan 2025 20:58:39 +0000
Subject: [PATCH 15/21] docs: more typo fixes (#483)
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 20c1dbb3..27c3a725 100644
--- a/README.md
+++ b/README.md
@@ -328,7 +328,7 @@ customer = response.parse() # get the object that `customers.create()` would ha
print(customer.id)
```
-These methods return a [`LegagcyAPIResponse`](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
From a429148a83f0e51afcb0b99d5661c706023da48f Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 8 Jan 2025 20:59:24 +0000
Subject: [PATCH 16/21] chore(internal): codegen related update (#484)
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 27c3a725..b141afdf 100644
--- a/README.md
+++ b/README.md
@@ -439,7 +439,7 @@ with Orb() as client:
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.
From 7a80005983ff3799ea685034dd750c08c74704e7 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 10 Jan 2025 16:54:56 +0000
Subject: [PATCH 17/21] fix: correctly handle deserialising `cls` fields (#485)
---
src/orb/_models.py | 8 ++++----
tests/test_models.py | 10 ++++++++++
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/src/orb/_models.py b/src/orb/_models.py
index d56ea1d9..9a918aab 100644
--- a/src/orb/_models.py
+++ b/src/orb/_models.py
@@ -179,14 +179,14 @@ def __str__(self) -> str:
@classmethod
@override
def construct( # pyright: ignore[reportIncompatibleMethodOverride]
- cls: Type[ModelT],
+ __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)
@@ -196,7 +196,7 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride]
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):
diff --git a/tests/test_models.py b/tests/test_models.py
index 52caebb2..011b9f92 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -844,3 +844,13 @@ class Model(BaseModel):
assert m.alias == "foo"
assert isinstance(m.union, str)
assert m.union == "bar"
+
+
+@pytest.mark.skipif(not PYDANTIC_V2, 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)
From be53793ecadc6adbda0baab9c7b47b15a0b585ec Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 13 Jan 2025 20:04:42 +0000
Subject: [PATCH 18/21] codegen metadata
---
.stats.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.stats.yml b/.stats.yml
index 7dd05a09..b1872c09 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
configured_endpoints: 101
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-52bd3046e73f201c4d08edfa92756791c015be907691a7893f8e7782cc2aea6f.yml
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-1720084d65e39f50455fe3a8756afc68fedf57306a727f92e4d020c28878df87.yml
From 4677063f95f37b7b982816871d8fa98871efd15f Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 14 Jan 2025 11:48:17 +0000
Subject: [PATCH 19/21] chore(internal): update deps (#486)
---
mypy.ini | 2 +-
requirements-dev.lock | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/mypy.ini b/mypy.ini
index 4f22c5a2..35b50327 100644
--- a/mypy.ini
+++ b/mypy.ini
@@ -41,7 +41,7 @@ cache_fine_grained = True
# ```
# Changing this codegen to make mypy happy would increase complexity
# and would not be worth it.
-disable_error_code = func-returns-value
+disable_error_code = func-returns-value,overload-cannot-match
# https://github.com/python/mypy/issues/12162
[mypy.overrides]
diff --git a/requirements-dev.lock b/requirements-dev.lock
index 29b7f1c5..efeb6441 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -48,7 +48,7 @@ markdown-it-py==3.0.0
# via rich
mdurl==0.1.2
# via markdown-it-py
-mypy==1.13.0
+mypy==1.14.1
mypy-extensions==1.0.0
# via mypy
nest-asyncio==1.6.0
@@ -68,7 +68,7 @@ pydantic-core==2.27.1
# via pydantic
pygments==2.18.0
# via rich
-pyright==1.1.390
+pyright==1.1.391
pytest==8.3.3
# via pytest-asyncio
pytest-asyncio==0.24.0
From 667a330e4074c66434a19d25fdfaf2a710f2d2c8 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 15 Jan 2025 15:45:09 +0000
Subject: [PATCH 20/21] chore(internal): bump pyright dependency (#487)
---
requirements-dev.lock | 2 +-
src/orb/_legacy_response.py | 12 ++++++++++--
src/orb/_response.py | 8 +++++++-
3 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/requirements-dev.lock b/requirements-dev.lock
index efeb6441..172ccf7f 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -68,7 +68,7 @@ pydantic-core==2.27.1
# via pydantic
pygments==2.18.0
# via rich
-pyright==1.1.391
+pyright==1.1.392.post0
pytest==8.3.3
# via pytest-asyncio
pytest-asyncio==0.24.0
diff --git a/src/orb/_legacy_response.py b/src/orb/_legacy_response.py
index 4cbb4ddf..1be09f02 100644
--- a/src/orb/_legacy_response.py
+++ b/src/orb/_legacy_response.py
@@ -262,7 +262,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
@@ -272,7 +274,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 (
diff --git a/src/orb/_response.py b/src/orb/_response.py
index 20f3cd4d..cefbd234 100644
--- a/src/orb/_response.py
+++ b/src/orb/_response.py
@@ -214,7 +214,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 (
From dd096711008701686dd8831c5d13d269f7718d91 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 15 Jan 2025 15:45:35 +0000
Subject: [PATCH 21/21] release: 2.21.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 36 +++++++++++++++++++++++++++++++++++
pyproject.toml | 2 +-
src/orb/_version.py | 2 +-
4 files changed, 39 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index da2177c6..02bd31d3 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "2.20.0"
+ ".": "2.21.0"
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 30d467ce..24b87d4d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,41 @@
# Changelog
+## 2.21.0 (2025-01-15)
+
+Full Changelog: [v2.20.0...v2.21.0](https://github.com/orbcorp/orb-python/compare/v2.20.0...v2.21.0)
+
+### Features
+
+* **api:** api update ([#471](https://github.com/orbcorp/orb-python/issues/471)) ([d23ec0e](https://github.com/orbcorp/orb-python/commit/d23ec0e08cc5e8bd681a8c7947778a8445b81f78))
+* **api:** api update ([#472](https://github.com/orbcorp/orb-python/issues/472)) ([0a22350](https://github.com/orbcorp/orb-python/commit/0a2235016cfba90da5f68e950579d0720bd40045))
+* **api:** api update ([#474](https://github.com/orbcorp/orb-python/issues/474)) ([d2fb2aa](https://github.com/orbcorp/orb-python/commit/d2fb2aa50c27160a8fd386aec812e8f3ace527fe))
+* **api:** api update ([#477](https://github.com/orbcorp/orb-python/issues/477)) ([59c3a8b](https://github.com/orbcorp/orb-python/commit/59c3a8bdfa3b18311e956511afd31d211c6f320d))
+* **api:** api update ([#478](https://github.com/orbcorp/orb-python/issues/478)) ([4036eca](https://github.com/orbcorp/orb-python/commit/4036ecaf1d14f3c235c11ce1551490a86fab8066))
+
+
+### Bug Fixes
+
+* **client:** only call .close() when needed ([#481](https://github.com/orbcorp/orb-python/issues/481)) ([c14225c](https://github.com/orbcorp/orb-python/commit/c14225cd09e514dea91586874e851cf1933b9af5))
+* correctly handle deserialising `cls` fields ([#485](https://github.com/orbcorp/orb-python/issues/485)) ([7a80005](https://github.com/orbcorp/orb-python/commit/7a80005983ff3799ea685034dd750c08c74704e7))
+
+
+### Chores
+
+* add missing isclass check ([#476](https://github.com/orbcorp/orb-python/issues/476)) ([cafafe4](https://github.com/orbcorp/orb-python/commit/cafafe4cfdfd12d1bbad5d1fce0ad0b992741993))
+* **client:** simplify `Optional[object]` to just `object` ([#475](https://github.com/orbcorp/orb-python/issues/475)) ([f684ed4](https://github.com/orbcorp/orb-python/commit/f684ed42a5452933f4fe5a495b309a74267e4728))
+* **internal:** bump httpx dependency ([#480](https://github.com/orbcorp/orb-python/issues/480)) ([6b04dea](https://github.com/orbcorp/orb-python/commit/6b04deaf0406eb2130ca9f159d42f84bd5ecac4a))
+* **internal:** bump pyright dependency ([#487](https://github.com/orbcorp/orb-python/issues/487)) ([667a330](https://github.com/orbcorp/orb-python/commit/667a330e4074c66434a19d25fdfaf2a710f2d2c8))
+* **internal:** codegen related update ([#473](https://github.com/orbcorp/orb-python/issues/473)) ([c24985f](https://github.com/orbcorp/orb-python/commit/c24985f1ff9e87de455a4b862045701f6c646bab))
+* **internal:** codegen related update ([#484](https://github.com/orbcorp/orb-python/issues/484)) ([a429148](https://github.com/orbcorp/orb-python/commit/a429148a83f0e51afcb0b99d5661c706023da48f))
+* **internal:** update deps ([#486](https://github.com/orbcorp/orb-python/issues/486)) ([4677063](https://github.com/orbcorp/orb-python/commit/4677063f95f37b7b982816871d8fa98871efd15f))
+* **internal:** version bump ([#469](https://github.com/orbcorp/orb-python/issues/469)) ([e95eb1d](https://github.com/orbcorp/orb-python/commit/e95eb1d93a4990d3fe2d722abf05b4bfa558c745))
+
+
+### Documentation
+
+* fix typos ([#482](https://github.com/orbcorp/orb-python/issues/482)) ([b8a2ce6](https://github.com/orbcorp/orb-python/commit/b8a2ce60542927b91329a10dd2d39efac96d6d9b))
+* more typo fixes ([#483](https://github.com/orbcorp/orb-python/issues/483)) ([569ad30](https://github.com/orbcorp/orb-python/commit/569ad308f81bc99620d2d08b3afc4ea95f0fe8d5))
+
## 2.20.0 (2024-12-19)
Full Changelog: [v2.19.0...v2.20.0](https://github.com/orbcorp/orb-python/compare/v2.19.0...v2.20.0)
diff --git a/pyproject.toml b/pyproject.toml
index 6e3ae75c..c1f63b5e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "orb-billing"
-version = "2.20.0"
+version = "2.21.0"
description = "The official Python library for the orb API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/orb/_version.py b/src/orb/_version.py
index 4efdcb3d..db5740a0 100644
--- a/src/orb/_version.py
+++ b/src/orb/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "orb"
-__version__ = "2.20.0" # x-release-please-version
+__version__ = "2.21.0" # x-release-please-version