Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "3.21.0"
".": "3.22.0"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 114
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-faced218bf2dee89c8449bdb209e7090452d26c0646f0b998f84fe5bd3c4b7cb.yml
openapi_spec_hash: b3a957e9c012fad5093545f65614ea42
config_hash: e63f2d098e5d12f63ae4cd8270aa5c3c
configured_endpoints: 115
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-d513be954ba2cb57489bd048f93790cabb13849f0f04d328a5a15694c99550df.yml
openapi_spec_hash: 0d42694f412abf65defc3f88646a809c
config_hash: 1e2186b09e57d7d27b6ab5c8e6410b31
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## 3.22.0 (2025-06-02)

Full Changelog: [v3.21.0...v3.22.0](https://github.com/orbcorp/orb-python/compare/v3.21.0...v3.22.0)

### Features

* **api:** api update ([3deb3ab](https://github.com/orbcorp/orb-python/commit/3deb3ab6bf04d89551aa40deba99afcd29ee8099))
* **client:** add follow_redirects request option ([5185843](https://github.com/orbcorp/orb-python/commit/51858434884f222b3c9974529aaf1958e5fba808))


### Chores

* **docs:** remove reference to rye shell ([c0cdb68](https://github.com/orbcorp/orb-python/commit/c0cdb684679416fb188bc77f8e822f8bcb345b50))

## 3.21.0 (2025-05-30)

Full Changelog: [v3.20.0...v3.21.0](https://github.com/orbcorp/orb-python/compare/v3.20.0...v3.21.0)
Expand Down
3 changes: 1 addition & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ $ rye sync --all-features
You can then run scripts using `rye run python script.py` or by activating the virtual environment:

```sh
$ rye shell
# or manually activate - https://docs.python.org/3/library/venv.html#how-venvs-work
# Activate the virtual environment - https://docs.python.org/3/library/venv.html#how-venvs-work
$ source .venv/bin/activate

# now you can omit the `rye run` prefix
Expand Down
2 changes: 2 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ from orb.types import (
SubscriptionFetchCostsResponse,
SubscriptionFetchScheduleResponse,
SubscriptionPriceIntervalsResponse,
SubscriptionRedeemCouponResponse,
SubscriptionSchedulePlanChangeResponse,
SubscriptionTriggerPhaseResponse,
SubscriptionUnscheduleCancellationResponse,
Expand All @@ -386,6 +387,7 @@ Methods:
- <code title="get /subscriptions/{subscription_id}/schedule">client.subscriptions.<a href="./src/orb/resources/subscriptions.py">fetch_schedule</a>(subscription_id, \*\*<a href="src/orb/types/subscription_fetch_schedule_params.py">params</a>) -> <a href="./src/orb/types/subscription_fetch_schedule_response.py">SyncPage[SubscriptionFetchScheduleResponse]</a></code>
- <code title="get /subscriptions/{subscription_id}/usage">client.subscriptions.<a href="./src/orb/resources/subscriptions.py">fetch_usage</a>(subscription_id, \*\*<a href="src/orb/types/subscription_fetch_usage_params.py">params</a>) -> <a href="./src/orb/types/subscription_usage.py">SubscriptionUsage</a></code>
- <code title="post /subscriptions/{subscription_id}/price_intervals">client.subscriptions.<a href="./src/orb/resources/subscriptions.py">price_intervals</a>(subscription_id, \*\*<a href="src/orb/types/subscription_price_intervals_params.py">params</a>) -> <a href="./src/orb/types/subscription_price_intervals_response.py">SubscriptionPriceIntervalsResponse</a></code>
- <code title="post /subscriptions/{subscription_id}/redeem_coupon">client.subscriptions.<a href="./src/orb/resources/subscriptions.py">redeem_coupon</a>(subscription_id, \*\*<a href="src/orb/types/subscription_redeem_coupon_params.py">params</a>) -> <a href="./src/orb/types/subscription_redeem_coupon_response.py">SubscriptionRedeemCouponResponse</a></code>
- <code title="post /subscriptions/{subscription_id}/schedule_plan_change">client.subscriptions.<a href="./src/orb/resources/subscriptions.py">schedule_plan_change</a>(subscription_id, \*\*<a href="src/orb/types/subscription_schedule_plan_change_params.py">params</a>) -> <a href="./src/orb/types/subscription_schedule_plan_change_response.py">SubscriptionSchedulePlanChangeResponse</a></code>
- <code title="post /subscriptions/{subscription_id}/trigger_phase">client.subscriptions.<a href="./src/orb/resources/subscriptions.py">trigger_phase</a>(subscription_id, \*\*<a href="src/orb/types/subscription_trigger_phase_params.py">params</a>) -> <a href="./src/orb/types/subscription_trigger_phase_response.py">SubscriptionTriggerPhaseResponse</a></code>
- <code title="post /subscriptions/{subscription_id}/unschedule_cancellation">client.subscriptions.<a href="./src/orb/resources/subscriptions.py">unschedule_cancellation</a>(subscription_id) -> <a href="./src/orb/types/subscription_unschedule_cancellation_response.py">SubscriptionUnscheduleCancellationResponse</a></code>
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "orb-billing"
version = "3.21.0"
version = "3.22.0"
description = "The official Python library for the orb API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down
6 changes: 6 additions & 0 deletions src/orb/_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,9 @@ def request(
if self.custom_auth is not None:
kwargs["auth"] = self.custom_auth

if options.follow_redirects is not None:
kwargs["follow_redirects"] = options.follow_redirects

log.debug("Sending HTTP Request: %s %s", request.method, request.url)

response = None
Expand Down Expand Up @@ -1475,6 +1478,9 @@ async def request(
if self.custom_auth is not None:
kwargs["auth"] = self.custom_auth

if options.follow_redirects is not None:
kwargs["follow_redirects"] = options.follow_redirects

log.debug("Sending HTTP Request: %s %s", request.method, request.url)

response = None
Expand Down
2 changes: 2 additions & 0 deletions src/orb/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,7 @@ class FinalRequestOptionsInput(TypedDict, total=False):
idempotency_key: str
json_data: Body
extra_json: AnyMapping
follow_redirects: bool


@final
Expand All @@ -750,6 +751,7 @@ class FinalRequestOptions(pydantic.BaseModel):
files: Union[HttpxRequestFiles, None] = None
idempotency_key: Union[str, None] = None
post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven()
follow_redirects: Union[bool, None] = None

# It should be noted that we cannot use `json` here as that would override
# a BaseModel method in an incompatible fashion.
Expand Down
2 changes: 2 additions & 0 deletions src/orb/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class RequestOptions(TypedDict, total=False):
params: Query
extra_json: AnyMapping
idempotency_key: str
follow_redirects: bool


# Sentinel class used until PEP 0661 is accepted
Expand Down Expand Up @@ -217,3 +218,4 @@ class _GenericAlias(Protocol):

class HttpxSendArgs(TypedDict, total=False):
auth: httpx.Auth
follow_redirects: bool
2 changes: 1 addition & 1 deletion src/orb/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "orb"
__version__ = "3.21.0" # x-release-please-version
__version__ = "3.22.0" # x-release-please-version
138 changes: 138 additions & 0 deletions src/orb/resources/subscriptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
subscription_fetch_costs_params,
subscription_fetch_usage_params,
subscription_update_trial_params,
subscription_redeem_coupon_params,
subscription_trigger_phase_params,
subscription_fetch_schedule_params,
subscription_price_intervals_params,
Expand All @@ -37,6 +38,7 @@
from ..types.subscription_create_response import SubscriptionCreateResponse
from ..types.subscription_fetch_costs_response import SubscriptionFetchCostsResponse
from ..types.subscription_update_trial_response import SubscriptionUpdateTrialResponse
from ..types.subscription_redeem_coupon_response import SubscriptionRedeemCouponResponse
from ..types.subscription_trigger_phase_response import SubscriptionTriggerPhaseResponse
from ..types.subscription_fetch_schedule_response import SubscriptionFetchScheduleResponse
from ..types.subscription_price_intervals_response import SubscriptionPriceIntervalsResponse
Expand Down Expand Up @@ -1361,6 +1363,68 @@ def price_intervals(
cast_to=SubscriptionPriceIntervalsResponse,
)

def redeem_coupon(
self,
subscription_id: str,
*,
change_option: Literal["requested_date", "end_of_subscription_term", "immediate"],
coupon_id: str,
allow_invoice_credit_or_void: Optional[bool] | NotGiven = NOT_GIVEN,
change_date: Union[str, datetime, None] | 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,
) -> SubscriptionRedeemCouponResponse:
"""
Redeem a coupon effective at a given time.

Args:
coupon_id: Coupon ID to be redeemed for this subscription.

allow_invoice_credit_or_void: If false, this request will fail if it would void an issued invoice or create a
credit note. Consider using this as a safety mechanism if you do not expect
existing invoices to be changed.

change_date: The date that the coupon discount should take effect. This parameter can only be
passed if the `change_option` is `requested_date`.

extra_headers: Send extra headers

extra_query: Add additional query parameters to the request

extra_body: Add additional JSON properties to the request

timeout: Override the client-level default timeout for this request, in seconds

idempotency_key: Specify a custom idempotency key for this request
"""
if not subscription_id:
raise ValueError(f"Expected a non-empty value for `subscription_id` but received {subscription_id!r}")
return self._post(
f"/subscriptions/{subscription_id}/redeem_coupon",
body=maybe_transform(
{
"change_option": change_option,
"coupon_id": coupon_id,
"allow_invoice_credit_or_void": allow_invoice_credit_or_void,
"change_date": change_date,
},
subscription_redeem_coupon_params.SubscriptionRedeemCouponParams,
),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
idempotency_key=idempotency_key,
),
cast_to=SubscriptionRedeemCouponResponse,
)

def schedule_plan_change(
self,
subscription_id: str,
Expand Down Expand Up @@ -3385,6 +3449,68 @@ async def price_intervals(
cast_to=SubscriptionPriceIntervalsResponse,
)

async def redeem_coupon(
self,
subscription_id: str,
*,
change_option: Literal["requested_date", "end_of_subscription_term", "immediate"],
coupon_id: str,
allow_invoice_credit_or_void: Optional[bool] | NotGiven = NOT_GIVEN,
change_date: Union[str, datetime, None] | 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,
) -> SubscriptionRedeemCouponResponse:
"""
Redeem a coupon effective at a given time.

Args:
coupon_id: Coupon ID to be redeemed for this subscription.

allow_invoice_credit_or_void: If false, this request will fail if it would void an issued invoice or create a
credit note. Consider using this as a safety mechanism if you do not expect
existing invoices to be changed.

change_date: The date that the coupon discount should take effect. This parameter can only be
passed if the `change_option` is `requested_date`.

extra_headers: Send extra headers

extra_query: Add additional query parameters to the request

extra_body: Add additional JSON properties to the request

timeout: Override the client-level default timeout for this request, in seconds

idempotency_key: Specify a custom idempotency key for this request
"""
if not subscription_id:
raise ValueError(f"Expected a non-empty value for `subscription_id` but received {subscription_id!r}")
return await self._post(
f"/subscriptions/{subscription_id}/redeem_coupon",
body=await async_maybe_transform(
{
"change_option": change_option,
"coupon_id": coupon_id,
"allow_invoice_credit_or_void": allow_invoice_credit_or_void,
"change_date": change_date,
},
subscription_redeem_coupon_params.SubscriptionRedeemCouponParams,
),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
idempotency_key=idempotency_key,
),
cast_to=SubscriptionRedeemCouponResponse,
)

async def schedule_plan_change(
self,
subscription_id: str,
Expand Down Expand Up @@ -4132,6 +4258,9 @@ def __init__(self, subscriptions: Subscriptions) -> None:
self.price_intervals = _legacy_response.to_raw_response_wrapper(
subscriptions.price_intervals,
)
self.redeem_coupon = _legacy_response.to_raw_response_wrapper(
subscriptions.redeem_coupon,
)
self.schedule_plan_change = _legacy_response.to_raw_response_wrapper(
subscriptions.schedule_plan_change,
)
Expand Down Expand Up @@ -4186,6 +4315,9 @@ def __init__(self, subscriptions: AsyncSubscriptions) -> None:
self.price_intervals = _legacy_response.async_to_raw_response_wrapper(
subscriptions.price_intervals,
)
self.redeem_coupon = _legacy_response.async_to_raw_response_wrapper(
subscriptions.redeem_coupon,
)
self.schedule_plan_change = _legacy_response.async_to_raw_response_wrapper(
subscriptions.schedule_plan_change,
)
Expand Down Expand Up @@ -4240,6 +4372,9 @@ def __init__(self, subscriptions: Subscriptions) -> None:
self.price_intervals = to_streamed_response_wrapper(
subscriptions.price_intervals,
)
self.redeem_coupon = to_streamed_response_wrapper(
subscriptions.redeem_coupon,
)
self.schedule_plan_change = to_streamed_response_wrapper(
subscriptions.schedule_plan_change,
)
Expand Down Expand Up @@ -4294,6 +4429,9 @@ def __init__(self, subscriptions: AsyncSubscriptions) -> None:
self.price_intervals = async_to_streamed_response_wrapper(
subscriptions.price_intervals,
)
self.redeem_coupon = async_to_streamed_response_wrapper(
subscriptions.redeem_coupon,
)
self.schedule_plan_change = async_to_streamed_response_wrapper(
subscriptions.schedule_plan_change,
)
Expand Down
2 changes: 2 additions & 0 deletions src/orb/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,15 @@
from .subscription_update_trial_params import SubscriptionUpdateTrialParams as SubscriptionUpdateTrialParams
from .invoice_line_item_create_response import InvoiceLineItemCreateResponse as InvoiceLineItemCreateResponse
from .subscription_fetch_costs_response import SubscriptionFetchCostsResponse as SubscriptionFetchCostsResponse
from .subscription_redeem_coupon_params import SubscriptionRedeemCouponParams as SubscriptionRedeemCouponParams
from .subscription_trigger_phase_params import SubscriptionTriggerPhaseParams as SubscriptionTriggerPhaseParams
from .subscription_change_apply_response import SubscriptionChangeApplyResponse as SubscriptionChangeApplyResponse
from .subscription_fetch_schedule_params import SubscriptionFetchScheduleParams as SubscriptionFetchScheduleParams
from .subscription_update_trial_response import SubscriptionUpdateTrialResponse as SubscriptionUpdateTrialResponse
from .dimensional_price_group_list_params import DimensionalPriceGroupListParams as DimensionalPriceGroupListParams
from .subscription_change_cancel_response import SubscriptionChangeCancelResponse as SubscriptionChangeCancelResponse
from .subscription_price_intervals_params import SubscriptionPriceIntervalsParams as SubscriptionPriceIntervalsParams
from .subscription_redeem_coupon_response import SubscriptionRedeemCouponResponse as SubscriptionRedeemCouponResponse
from .subscription_trigger_phase_response import SubscriptionTriggerPhaseResponse as SubscriptionTriggerPhaseResponse
from .alert_create_for_subscription_params import AlertCreateForSubscriptionParams as AlertCreateForSubscriptionParams
from .beta_set_default_plan_version_params import BetaSetDefaultPlanVersionParams as BetaSetDefaultPlanVersionParams
Expand Down
2 changes: 1 addition & 1 deletion src/orb/types/invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,7 @@ class LineItem(BaseModel):
partially_invoiced_amount: str
"""Any amount applied from a partial invoice"""

price: Optional[Price] = None
price: Price
"""
The Price resource represents a price that can be billed on a subscription,
resulting in a charge on an invoice in the form of an invoice line item. Prices
Expand Down
2 changes: 1 addition & 1 deletion src/orb/types/invoice_fetch_upcoming_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,7 @@ class LineItem(BaseModel):
partially_invoiced_amount: str
"""Any amount applied from a partial invoice"""

price: Optional[Price] = None
price: Price
"""
The Price resource represents a price that can be billed on a subscription,
resulting in a charge on an invoice in the form of an invoice line item. Prices
Expand Down
2 changes: 1 addition & 1 deletion src/orb/types/invoice_line_item_create_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ class InvoiceLineItemCreateResponse(BaseModel):
partially_invoiced_amount: str
"""Any amount applied from a partial invoice"""

price: Optional[Price] = None
price: Price
"""
The Price resource represents a price that can be billed on a subscription,
resulting in a charge on an invoice in the form of an invoice line item. Prices
Expand Down
31 changes: 31 additions & 0 deletions src/orb/types/subscription_redeem_coupon_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from __future__ import annotations

from typing import Union, Optional
from datetime import datetime
from typing_extensions import Literal, Required, Annotated, TypedDict

from .._utils import PropertyInfo

__all__ = ["SubscriptionRedeemCouponParams"]


class SubscriptionRedeemCouponParams(TypedDict, total=False):
change_option: Required[Literal["requested_date", "end_of_subscription_term", "immediate"]]

coupon_id: Required[str]
"""Coupon ID to be redeemed for this subscription."""

allow_invoice_credit_or_void: Optional[bool]
"""
If false, this request will fail if it would void an issued invoice or create a
credit note. Consider using this as a safety mechanism if you do not expect
existing invoices to be changed.
"""

change_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]
"""The date that the coupon discount should take effect.

This parameter can only be passed if the `change_option` is `requested_date`.
"""
Loading