Skip to content

Commit 5f8379a

Browse files
feat(api): add beta evaluate price endpoint (#129)
1 parent 5fbd017 commit 5f8379a

File tree

16 files changed

+479
-362
lines changed

16 files changed

+479
-362
lines changed

.stats.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
configured_endpoints: 74
1+
configured_endpoints: 75

api.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,3 +312,17 @@ Methods:
312312
- <code title="post /subscriptions/{subscription_id}/unschedule_fixed_fee_quantity_updates">client.subscriptions.<a href="./src/orb/resources/subscriptions.py">unschedule_fixed_fee_quantity_updates</a>(subscription_id, \*\*<a href="src/orb/types/subscription_unschedule_fixed_fee_quantity_updates_params.py">params</a>) -> <a href="./src/orb/types/subscription.py">Subscription</a></code>
313313
- <code title="post /subscriptions/{subscription_id}/unschedule_pending_plan_changes">client.subscriptions.<a href="./src/orb/resources/subscriptions.py">unschedule_pending_plan_changes</a>(subscription_id) -> <a href="./src/orb/types/subscription.py">Subscription</a></code>
314314
- <code title="post /subscriptions/{subscription_id}/update_fixed_fee_quantity">client.subscriptions.<a href="./src/orb/resources/subscriptions.py">update_fixed_fee_quantity</a>(subscription_id, \*\*<a href="src/orb/types/subscription_update_fixed_fee_quantity_params.py">params</a>) -> <a href="./src/orb/types/subscription.py">Subscription</a></code>
315+
316+
# Beta
317+
318+
## Price
319+
320+
Types:
321+
322+
```python
323+
from orb.types.beta import EvaluatePriceGroup, PriceEvaluateResponse
324+
```
325+
326+
Methods:
327+
328+
- <code title="post /prices/{price_id}/evaluate">client.beta.price.<a href="./src/orb/resources/beta/price.py">evaluate</a>(price_id, \*\*<a href="src/orb/types/beta/price_evaluate_params.py">params</a>) -> <a href="./src/orb/types/beta/price_evaluate_response.py">PriceEvaluateResponse</a></code>

src/orb/_client.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class Orb(SyncAPIClient):
5959
plans: resources.Plans
6060
prices: resources.Prices
6161
subscriptions: resources.Subscriptions
62+
beta: resources.Beta
6263
with_raw_response: OrbWithRawResponse
6364

6465
# client options
@@ -127,6 +128,7 @@ def __init__(
127128
self.plans = resources.Plans(self)
128129
self.prices = resources.Prices(self)
129130
self.subscriptions = resources.Subscriptions(self)
131+
self.beta = resources.Beta(self)
130132
self.with_raw_response = OrbWithRawResponse(self)
131133

132134
@property
@@ -295,6 +297,7 @@ class AsyncOrb(AsyncAPIClient):
295297
plans: resources.AsyncPlans
296298
prices: resources.AsyncPrices
297299
subscriptions: resources.AsyncSubscriptions
300+
beta: resources.AsyncBeta
298301
with_raw_response: AsyncOrbWithRawResponse
299302

300303
# client options
@@ -363,6 +366,7 @@ def __init__(
363366
self.plans = resources.AsyncPlans(self)
364367
self.prices = resources.AsyncPrices(self)
365368
self.subscriptions = resources.AsyncSubscriptions(self)
369+
self.beta = resources.AsyncBeta(self)
366370
self.with_raw_response = AsyncOrbWithRawResponse(self)
367371

368372
@property
@@ -532,6 +536,7 @@ def __init__(self, client: Orb) -> None:
532536
self.plans = resources.PlansWithRawResponse(client.plans)
533537
self.prices = resources.PricesWithRawResponse(client.prices)
534538
self.subscriptions = resources.SubscriptionsWithRawResponse(client.subscriptions)
539+
self.beta = resources.BetaWithRawResponse(client.beta)
535540

536541

537542
class AsyncOrbWithRawResponse:
@@ -548,6 +553,7 @@ def __init__(self, client: AsyncOrb) -> None:
548553
self.plans = resources.AsyncPlansWithRawResponse(client.plans)
549554
self.prices = resources.AsyncPricesWithRawResponse(client.prices)
550555
self.subscriptions = resources.AsyncSubscriptionsWithRawResponse(client.subscriptions)
556+
self.beta = resources.AsyncBetaWithRawResponse(client.beta)
551557

552558

553559
Client = Orb

src/orb/resources/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# File generated from our OpenAPI spec by Stainless.
22

3+
from .beta import Beta, AsyncBeta, BetaWithRawResponse, AsyncBetaWithRawResponse
34
from .items import Items, AsyncItems, ItemsWithRawResponse, AsyncItemsWithRawResponse
45
from .plans import Plans, AsyncPlans, PlansWithRawResponse, AsyncPlansWithRawResponse
56
from .events import Events, AsyncEvents, EventsWithRawResponse, AsyncEventsWithRawResponse
@@ -72,4 +73,8 @@
7273
"AsyncSubscriptions",
7374
"SubscriptionsWithRawResponse",
7475
"AsyncSubscriptionsWithRawResponse",
76+
"Beta",
77+
"AsyncBeta",
78+
"BetaWithRawResponse",
79+
"AsyncBetaWithRawResponse",
7580
]

src/orb/resources/beta/__init__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# File generated from our OpenAPI spec by Stainless.
2+
3+
from .beta import Beta, AsyncBeta, BetaWithRawResponse, AsyncBetaWithRawResponse
4+
from .price import Price, AsyncPrice, PriceWithRawResponse, AsyncPriceWithRawResponse
5+
6+
__all__ = [
7+
"Price",
8+
"AsyncPrice",
9+
"PriceWithRawResponse",
10+
"AsyncPriceWithRawResponse",
11+
"Beta",
12+
"AsyncBeta",
13+
"BetaWithRawResponse",
14+
"AsyncBetaWithRawResponse",
15+
]

src/orb/resources/beta/beta.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# File generated from our OpenAPI spec by Stainless.
2+
3+
from __future__ import annotations
4+
5+
from .price import Price, AsyncPrice, PriceWithRawResponse, AsyncPriceWithRawResponse
6+
from ..._compat import cached_property
7+
from ..._resource import SyncAPIResource, AsyncAPIResource
8+
9+
__all__ = ["Beta", "AsyncBeta"]
10+
11+
12+
class Beta(SyncAPIResource):
13+
@cached_property
14+
def price(self) -> Price:
15+
return Price(self._client)
16+
17+
@cached_property
18+
def with_raw_response(self) -> BetaWithRawResponse:
19+
return BetaWithRawResponse(self)
20+
21+
22+
class AsyncBeta(AsyncAPIResource):
23+
@cached_property
24+
def price(self) -> AsyncPrice:
25+
return AsyncPrice(self._client)
26+
27+
@cached_property
28+
def with_raw_response(self) -> AsyncBetaWithRawResponse:
29+
return AsyncBetaWithRawResponse(self)
30+
31+
32+
class BetaWithRawResponse:
33+
def __init__(self, beta: Beta) -> None:
34+
self.price = PriceWithRawResponse(beta.price)
35+
36+
37+
class AsyncBetaWithRawResponse:
38+
def __init__(self, beta: AsyncBeta) -> None:
39+
self.price = AsyncPriceWithRawResponse(beta.price)

src/orb/resources/beta/price.py

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
# File generated from our OpenAPI spec by Stainless.
2+
3+
from __future__ import annotations
4+
5+
from typing import List, Union, Optional
6+
from datetime import datetime
7+
8+
import httpx
9+
10+
from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
11+
from ..._utils import maybe_transform
12+
from ..._compat import cached_property
13+
from ..._resource import SyncAPIResource, AsyncAPIResource
14+
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
15+
from ...types.beta import PriceEvaluateResponse, price_evaluate_params
16+
from ..._base_client import (
17+
make_request_options,
18+
)
19+
20+
__all__ = ["Price", "AsyncPrice"]
21+
22+
23+
class Price(SyncAPIResource):
24+
@cached_property
25+
def with_raw_response(self) -> PriceWithRawResponse:
26+
return PriceWithRawResponse(self)
27+
28+
def evaluate(
29+
self,
30+
price_id: str,
31+
*,
32+
timeframe_end: Union[str, datetime],
33+
timeframe_start: Union[str, datetime],
34+
customer_id: Optional[str] | NotGiven = NOT_GIVEN,
35+
external_customer_id: Optional[str] | NotGiven = NOT_GIVEN,
36+
filter: Optional[str] | NotGiven = NOT_GIVEN,
37+
grouping_keys: List[str] | NotGiven = NOT_GIVEN,
38+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
39+
# The extra values given here take precedence over values defined on the client or passed to this method.
40+
extra_headers: Headers | None = None,
41+
extra_query: Query | None = None,
42+
extra_body: Body | None = None,
43+
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
44+
idempotency_key: str | None = None,
45+
) -> PriceEvaluateResponse:
46+
"""
47+
This endpoint is used to evaluate the output of a price for a given customer and
48+
time range. It enables filtering and grouping the output using
49+
[computed properties](../guides/extensibility/advanced-metrics#computed-properties),
50+
supporting the following workflows:
51+
52+
1. Showing detailed usage and costs to the end customer.
53+
2. Auditing subtotals on invoice line items.
54+
55+
For these workflows, the expressiveness of computed properties in both the
56+
filters and grouping is critical. For example, if you'd like to show your
57+
customer their usage grouped by hour and another property, you can do so with
58+
the following `grouping_keys`:
59+
`["hour_floor_timestamp_millis(timestamp_millis)", "my_property"]`. If you'd
60+
like to examine a customer's usage for a specific property value, you can do so
61+
with the following `filter`:
62+
`my_property = 'foo' AND my_other_property = 'bar'`.
63+
64+
By default, the start of the time range must be no more than 100 days ago and
65+
the length of the results must be no greater than 1000. Note that this is a POST
66+
endpoint rather than a GET endpoint because it employs a JSON body rather than
67+
query parameters.
68+
69+
Args:
70+
timeframe_end: The exclusive upper bound for event timestamps
71+
72+
timeframe_start: The inclusive lower bound for event timestamps
73+
74+
customer_id: The ID of the customer to which this evaluation is scoped.
75+
76+
external_customer_id: The external customer ID of the customer to which this evaluation is scoped.
77+
78+
filter: A boolean
79+
[computed property](../guides/extensibility/advanced-metrics#computed-properties)
80+
used to filter the underlying billable metric
81+
82+
grouping_keys: Properties (or
83+
[computed properties](../guides/extensibility/advanced-metrics#computed-properties))
84+
used to group the underlying billable metric
85+
86+
extra_headers: Send extra headers
87+
88+
extra_query: Add additional query parameters to the request
89+
90+
extra_body: Add additional JSON properties to the request
91+
92+
timeout: Override the client-level default timeout for this request, in seconds
93+
94+
idempotency_key: Specify a custom idempotency key for this request
95+
"""
96+
return self._post(
97+
f"/prices/{price_id}/evaluate",
98+
body=maybe_transform(
99+
{
100+
"timeframe_end": timeframe_end,
101+
"timeframe_start": timeframe_start,
102+
"customer_id": customer_id,
103+
"external_customer_id": external_customer_id,
104+
"filter": filter,
105+
"grouping_keys": grouping_keys,
106+
},
107+
price_evaluate_params.PriceEvaluateParams,
108+
),
109+
options=make_request_options(
110+
extra_headers=extra_headers,
111+
extra_query=extra_query,
112+
extra_body=extra_body,
113+
timeout=timeout,
114+
idempotency_key=idempotency_key,
115+
),
116+
cast_to=PriceEvaluateResponse,
117+
)
118+
119+
120+
class AsyncPrice(AsyncAPIResource):
121+
@cached_property
122+
def with_raw_response(self) -> AsyncPriceWithRawResponse:
123+
return AsyncPriceWithRawResponse(self)
124+
125+
async def evaluate(
126+
self,
127+
price_id: str,
128+
*,
129+
timeframe_end: Union[str, datetime],
130+
timeframe_start: Union[str, datetime],
131+
customer_id: Optional[str] | NotGiven = NOT_GIVEN,
132+
external_customer_id: Optional[str] | NotGiven = NOT_GIVEN,
133+
filter: Optional[str] | NotGiven = NOT_GIVEN,
134+
grouping_keys: List[str] | NotGiven = NOT_GIVEN,
135+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
136+
# The extra values given here take precedence over values defined on the client or passed to this method.
137+
extra_headers: Headers | None = None,
138+
extra_query: Query | None = None,
139+
extra_body: Body | None = None,
140+
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
141+
idempotency_key: str | None = None,
142+
) -> PriceEvaluateResponse:
143+
"""
144+
This endpoint is used to evaluate the output of a price for a given customer and
145+
time range. It enables filtering and grouping the output using
146+
[computed properties](../guides/extensibility/advanced-metrics#computed-properties),
147+
supporting the following workflows:
148+
149+
1. Showing detailed usage and costs to the end customer.
150+
2. Auditing subtotals on invoice line items.
151+
152+
For these workflows, the expressiveness of computed properties in both the
153+
filters and grouping is critical. For example, if you'd like to show your
154+
customer their usage grouped by hour and another property, you can do so with
155+
the following `grouping_keys`:
156+
`["hour_floor_timestamp_millis(timestamp_millis)", "my_property"]`. If you'd
157+
like to examine a customer's usage for a specific property value, you can do so
158+
with the following `filter`:
159+
`my_property = 'foo' AND my_other_property = 'bar'`.
160+
161+
By default, the start of the time range must be no more than 100 days ago and
162+
the length of the results must be no greater than 1000. Note that this is a POST
163+
endpoint rather than a GET endpoint because it employs a JSON body rather than
164+
query parameters.
165+
166+
Args:
167+
timeframe_end: The exclusive upper bound for event timestamps
168+
169+
timeframe_start: The inclusive lower bound for event timestamps
170+
171+
customer_id: The ID of the customer to which this evaluation is scoped.
172+
173+
external_customer_id: The external customer ID of the customer to which this evaluation is scoped.
174+
175+
filter: A boolean
176+
[computed property](../guides/extensibility/advanced-metrics#computed-properties)
177+
used to filter the underlying billable metric
178+
179+
grouping_keys: Properties (or
180+
[computed properties](../guides/extensibility/advanced-metrics#computed-properties))
181+
used to group the underlying billable metric
182+
183+
extra_headers: Send extra headers
184+
185+
extra_query: Add additional query parameters to the request
186+
187+
extra_body: Add additional JSON properties to the request
188+
189+
timeout: Override the client-level default timeout for this request, in seconds
190+
191+
idempotency_key: Specify a custom idempotency key for this request
192+
"""
193+
return await self._post(
194+
f"/prices/{price_id}/evaluate",
195+
body=maybe_transform(
196+
{
197+
"timeframe_end": timeframe_end,
198+
"timeframe_start": timeframe_start,
199+
"customer_id": customer_id,
200+
"external_customer_id": external_customer_id,
201+
"filter": filter,
202+
"grouping_keys": grouping_keys,
203+
},
204+
price_evaluate_params.PriceEvaluateParams,
205+
),
206+
options=make_request_options(
207+
extra_headers=extra_headers,
208+
extra_query=extra_query,
209+
extra_body=extra_body,
210+
timeout=timeout,
211+
idempotency_key=idempotency_key,
212+
),
213+
cast_to=PriceEvaluateResponse,
214+
)
215+
216+
217+
class PriceWithRawResponse:
218+
def __init__(self, price: Price) -> None:
219+
self.evaluate = to_raw_response_wrapper(
220+
price.evaluate,
221+
)
222+
223+
224+
class AsyncPriceWithRawResponse:
225+
def __init__(self, price: AsyncPrice) -> None:
226+
self.evaluate = async_to_raw_response_wrapper(
227+
price.evaluate,
228+
)

src/orb/types/beta/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# File generated from our OpenAPI spec by Stainless.
2+
3+
from __future__ import annotations
4+
5+
from .evaluate_price_group import EvaluatePriceGroup as EvaluatePriceGroup
6+
from .price_evaluate_params import PriceEvaluateParams as PriceEvaluateParams
7+
from .price_evaluate_response import PriceEvaluateResponse as PriceEvaluateResponse
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# File generated from our OpenAPI spec by Stainless.
2+
3+
from typing import List, Union
4+
5+
from ..._models import BaseModel
6+
7+
__all__ = ["EvaluatePriceGroup"]
8+
9+
10+
class EvaluatePriceGroup(BaseModel):
11+
amount: str
12+
"""The price's output for the group"""
13+
14+
grouping_values: List[Union[str, float, bool]]
15+
"""The values for the group in the order specified by `grouping_keys`"""
16+
17+
quantity: float
18+
"""The price's usage quantity for the group"""

0 commit comments

Comments
 (0)