diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 9183c177..7553ced8 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "4.47.0"
+ ".": "4.48.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 8f4293ee..df8db457 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 118
+configured_endpoints: 126
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-a5a28a58483355d3cc3da7ac5c452d548ee17183324318198052968121ca7dba.yml
openapi_spec_hash: a317931a99e6d4a122919135a0363e40
-config_hash: 05c94c0e6dbeab2c9b554c2e0d6371a0
+config_hash: bcf82bddb691f6be773ac6cae8c03b9a
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 775a94da..af9f7bf7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## 4.48.0 (2026-01-08)
+
+Full Changelog: [v4.47.0...v4.48.0](https://github.com/orbcorp/orb-python/compare/v4.47.0...v4.48.0)
+
+### Features
+
+* **api:** manual updates ([19e971e](https://github.com/orbcorp/orb-python/commit/19e971ed6f2da625b7d29101aa3ae8aab99e4401))
+
## 4.47.0 (2026-01-06)
Full Changelog: [v4.46.3...v4.47.0](https://github.com/orbcorp/orb-python/compare/v4.46.3...v4.47.0)
diff --git a/api.md b/api.md
index 5081e822..cff6ca7b 100644
--- a/api.md
+++ b/api.md
@@ -389,7 +389,7 @@ Methods:
Types:
```python
-from orb.types import InvoiceFetchUpcomingResponse
+from orb.types import InvoiceFetchUpcomingResponse, InvoiceListSummaryResponse
```
Methods:
@@ -397,9 +397,11 @@ Methods:
- client.invoices.create(\*\*params) -> Invoice
- client.invoices.update(invoice_id, \*\*params) -> Invoice
- client.invoices.list(\*\*params) -> SyncPage[Invoice]
+- client.invoices.delete_line_item(line_item_id, \*, invoice_id) -> None
- client.invoices.fetch(invoice_id) -> Invoice
- client.invoices.fetch_upcoming(\*\*params) -> InvoiceFetchUpcomingResponse
- client.invoices.issue(invoice_id, \*\*params) -> Invoice
+- client.invoices.list_summary(\*\*params) -> SyncPage[InvoiceListSummaryResponse]
- client.invoices.mark_paid(invoice_id, \*\*params) -> Invoice
- client.invoices.pay(invoice_id) -> Invoice
- client.invoices.void(invoice_id) -> Invoice
@@ -457,6 +459,24 @@ Methods:
- client.plans.external_plan_id.update(other_external_plan_id, \*\*params) -> Plan
- client.plans.external_plan_id.fetch(external_plan_id) -> Plan
+## Migrations
+
+Types:
+
+```python
+from orb.types.plans import (
+ MigrationRetrieveResponse,
+ MigrationListResponse,
+ MigrationCancelResponse,
+)
+```
+
+Methods:
+
+- client.plans.migrations.retrieve(migration_id, \*, plan_id) -> MigrationRetrieveResponse
+- client.plans.migrations.list(plan_id, \*\*params) -> SyncPage[MigrationListResponse]
+- client.plans.migrations.cancel(migration_id, \*, plan_id) -> MigrationCancelResponse
+
# Prices
Types:
@@ -603,6 +623,7 @@ Types:
from orb.types import (
MutatedSubscription,
SubscriptionChangeRetrieveResponse,
+ SubscriptionChangeListResponse,
SubscriptionChangeApplyResponse,
SubscriptionChangeCancelResponse,
)
@@ -611,5 +632,19 @@ from orb.types import (
Methods:
- client.subscription_changes.retrieve(subscription_change_id) -> SubscriptionChangeRetrieveResponse
+- client.subscription_changes.list(\*\*params) -> SyncPage[SubscriptionChangeListResponse]
- client.subscription_changes.apply(subscription_change_id, \*\*params) -> SubscriptionChangeApplyResponse
- client.subscription_changes.cancel(subscription_change_id) -> SubscriptionChangeCancelResponse
+
+# CreditBlocks
+
+Types:
+
+```python
+from orb.types import CreditBlockRetrieveResponse
+```
+
+Methods:
+
+- client.credit_blocks.retrieve(block_id) -> CreditBlockRetrieveResponse
+- client.credit_blocks.delete(block_id) -> None
diff --git a/pyproject.toml b/pyproject.toml
index f8f576e3..e783c6e6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "orb-billing"
-version = "4.47.0"
+version = "4.48.0"
description = "The official Python library for the orb API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/orb/_client.py b/src/orb/_client.py
index 988bde1a..63d77496 100644
--- a/src/orb/_client.py
+++ b/src/orb/_client.py
@@ -49,6 +49,7 @@
customers,
top_level,
credit_notes,
+ credit_blocks,
subscriptions,
invoice_line_items,
subscription_changes,
@@ -62,6 +63,7 @@
from .resources.top_level import TopLevel, AsyncTopLevel
from .resources.plans.plans import Plans, AsyncPlans
from .resources.credit_notes import CreditNotes, AsyncCreditNotes
+ from .resources.credit_blocks import CreditBlocks, AsyncCreditBlocks
from .resources.events.events import Events, AsyncEvents
from .resources.prices.prices import Prices, AsyncPrices
from .resources.subscriptions import Subscriptions, AsyncSubscriptions
@@ -244,6 +246,12 @@ def webhooks(self) -> webhooks.Webhooks:
return Webhooks(self)
+ @cached_property
+ def credit_blocks(self) -> CreditBlocks:
+ from .resources.credit_blocks import CreditBlocks
+
+ return CreditBlocks(self)
+
@cached_property
def with_raw_response(self) -> OrbWithRawResponse:
return OrbWithRawResponse(self)
@@ -574,6 +582,12 @@ def webhooks(self) -> webhooks.AsyncWebhooks:
return AsyncWebhooks(self)
+ @cached_property
+ def credit_blocks(self) -> AsyncCreditBlocks:
+ from .resources.credit_blocks import AsyncCreditBlocks
+
+ return AsyncCreditBlocks(self)
+
@cached_property
def with_raw_response(self) -> AsyncOrbWithRawResponse:
return AsyncOrbWithRawResponse(self)
@@ -839,6 +853,12 @@ def subscription_changes(self) -> subscription_changes.SubscriptionChangesWithRa
return SubscriptionChangesWithRawResponse(self._client.subscription_changes)
+ @cached_property
+ def credit_blocks(self) -> credit_blocks.CreditBlocksWithRawResponse:
+ from .resources.credit_blocks import CreditBlocksWithRawResponse
+
+ return CreditBlocksWithRawResponse(self._client.credit_blocks)
+
class AsyncOrbWithRawResponse:
_client: AsyncOrb
@@ -942,6 +962,12 @@ def subscription_changes(self) -> subscription_changes.AsyncSubscriptionChangesW
return AsyncSubscriptionChangesWithRawResponse(self._client.subscription_changes)
+ @cached_property
+ def credit_blocks(self) -> credit_blocks.AsyncCreditBlocksWithRawResponse:
+ from .resources.credit_blocks import AsyncCreditBlocksWithRawResponse
+
+ return AsyncCreditBlocksWithRawResponse(self._client.credit_blocks)
+
class OrbWithStreamedResponse:
_client: Orb
@@ -1045,6 +1071,12 @@ def subscription_changes(self) -> subscription_changes.SubscriptionChangesWithSt
return SubscriptionChangesWithStreamingResponse(self._client.subscription_changes)
+ @cached_property
+ def credit_blocks(self) -> credit_blocks.CreditBlocksWithStreamingResponse:
+ from .resources.credit_blocks import CreditBlocksWithStreamingResponse
+
+ return CreditBlocksWithStreamingResponse(self._client.credit_blocks)
+
class AsyncOrbWithStreamedResponse:
_client: AsyncOrb
@@ -1148,6 +1180,12 @@ def subscription_changes(self) -> subscription_changes.AsyncSubscriptionChangesW
return AsyncSubscriptionChangesWithStreamingResponse(self._client.subscription_changes)
+ @cached_property
+ def credit_blocks(self) -> credit_blocks.AsyncCreditBlocksWithStreamingResponse:
+ from .resources.credit_blocks import AsyncCreditBlocksWithStreamingResponse
+
+ return AsyncCreditBlocksWithStreamingResponse(self._client.credit_blocks)
+
Client = Orb
diff --git a/src/orb/_version.py b/src/orb/_version.py
index 114fe4d7..1a499960 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__ = "4.47.0" # x-release-please-version
+__version__ = "4.48.0" # x-release-please-version
diff --git a/src/orb/resources/__init__.py b/src/orb/resources/__init__.py
index 09ab61de..581b66b6 100644
--- a/src/orb/resources/__init__.py
+++ b/src/orb/resources/__init__.py
@@ -100,6 +100,14 @@
CreditNotesWithStreamingResponse,
AsyncCreditNotesWithStreamingResponse,
)
+from .credit_blocks import (
+ CreditBlocks,
+ AsyncCreditBlocks,
+ CreditBlocksWithRawResponse,
+ AsyncCreditBlocksWithRawResponse,
+ CreditBlocksWithStreamingResponse,
+ AsyncCreditBlocksWithStreamingResponse,
+)
from .subscriptions import (
Subscriptions,
AsyncSubscriptions,
@@ -232,4 +240,10 @@
"AsyncSubscriptionChangesWithRawResponse",
"SubscriptionChangesWithStreamingResponse",
"AsyncSubscriptionChangesWithStreamingResponse",
+ "CreditBlocks",
+ "AsyncCreditBlocks",
+ "CreditBlocksWithRawResponse",
+ "AsyncCreditBlocksWithRawResponse",
+ "CreditBlocksWithStreamingResponse",
+ "AsyncCreditBlocksWithStreamingResponse",
]
diff --git a/src/orb/resources/credit_blocks.py b/src/orb/resources/credit_blocks.py
new file mode 100644
index 00000000..5dbec7f4
--- /dev/null
+++ b/src/orb/resources/credit_blocks.py
@@ -0,0 +1,281 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from .. import _legacy_response
+from .._types import Body, Query, Headers, NoneType, NotGiven, not_given
+from .._compat import cached_property
+from .._resource import SyncAPIResource, AsyncAPIResource
+from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from .._base_client import make_request_options
+from ..types.credit_block_retrieve_response import CreditBlockRetrieveResponse
+
+__all__ = ["CreditBlocks", "AsyncCreditBlocks"]
+
+
+class CreditBlocks(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> CreditBlocksWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers
+ """
+ return CreditBlocksWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> CreditBlocksWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response
+ """
+ return CreditBlocksWithStreamingResponse(self)
+
+ def retrieve(
+ self,
+ block_id: str,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> CreditBlockRetrieveResponse:
+ """
+ This endpoint returns a credit block identified by its block_id.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not block_id:
+ raise ValueError(f"Expected a non-empty value for `block_id` but received {block_id!r}")
+ return self._get(
+ f"/credit_blocks/{block_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=CreditBlockRetrieveResponse,
+ )
+
+ def delete(
+ self,
+ block_id: str,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ idempotency_key: str | None = None,
+ ) -> None:
+ """
+ This endpoint deletes a credit block by its ID.
+
+ When a credit block is deleted:
+
+ - The block is removed from the customer's credit ledger.
+ - Any usage of the credit block is reversed, and the ledger is replayed as if
+ the block never existed.
+ - If invoices were generated from the purchase of the credit block, they will be
+ deleted if in draft status, voided if issued, or a credit note will be issued
+ if the invoice is paid.
+
+
+ Issued invoices that had credits applied from this block will not be regenerated, but the ledger will
+ reflect the state as if credits from the deleted block were never applied.
+
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+
+ idempotency_key: Specify a custom idempotency key for this request
+ """
+ if not block_id:
+ raise ValueError(f"Expected a non-empty value for `block_id` but received {block_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return self._delete(
+ f"/credit_blocks/{block_id}",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=NoneType,
+ )
+
+
+class AsyncCreditBlocks(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncCreditBlocksWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncCreditBlocksWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncCreditBlocksWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response
+ """
+ return AsyncCreditBlocksWithStreamingResponse(self)
+
+ async def retrieve(
+ self,
+ block_id: str,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> CreditBlockRetrieveResponse:
+ """
+ This endpoint returns a credit block identified by its block_id.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not block_id:
+ raise ValueError(f"Expected a non-empty value for `block_id` but received {block_id!r}")
+ return await self._get(
+ f"/credit_blocks/{block_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=CreditBlockRetrieveResponse,
+ )
+
+ async def delete(
+ self,
+ block_id: str,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ idempotency_key: str | None = None,
+ ) -> None:
+ """
+ This endpoint deletes a credit block by its ID.
+
+ When a credit block is deleted:
+
+ - The block is removed from the customer's credit ledger.
+ - Any usage of the credit block is reversed, and the ledger is replayed as if
+ the block never existed.
+ - If invoices were generated from the purchase of the credit block, they will be
+ deleted if in draft status, voided if issued, or a credit note will be issued
+ if the invoice is paid.
+
+
+ Issued invoices that had credits applied from this block will not be regenerated, but the ledger will
+ reflect the state as if credits from the deleted block were never applied.
+
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+
+ idempotency_key: Specify a custom idempotency key for this request
+ """
+ if not block_id:
+ raise ValueError(f"Expected a non-empty value for `block_id` but received {block_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return await self._delete(
+ f"/credit_blocks/{block_id}",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=NoneType,
+ )
+
+
+class CreditBlocksWithRawResponse:
+ def __init__(self, credit_blocks: CreditBlocks) -> None:
+ self._credit_blocks = credit_blocks
+
+ self.retrieve = _legacy_response.to_raw_response_wrapper(
+ credit_blocks.retrieve,
+ )
+ self.delete = _legacy_response.to_raw_response_wrapper(
+ credit_blocks.delete,
+ )
+
+
+class AsyncCreditBlocksWithRawResponse:
+ def __init__(self, credit_blocks: AsyncCreditBlocks) -> None:
+ self._credit_blocks = credit_blocks
+
+ self.retrieve = _legacy_response.async_to_raw_response_wrapper(
+ credit_blocks.retrieve,
+ )
+ self.delete = _legacy_response.async_to_raw_response_wrapper(
+ credit_blocks.delete,
+ )
+
+
+class CreditBlocksWithStreamingResponse:
+ def __init__(self, credit_blocks: CreditBlocks) -> None:
+ self._credit_blocks = credit_blocks
+
+ self.retrieve = to_streamed_response_wrapper(
+ credit_blocks.retrieve,
+ )
+ self.delete = to_streamed_response_wrapper(
+ credit_blocks.delete,
+ )
+
+
+class AsyncCreditBlocksWithStreamingResponse:
+ def __init__(self, credit_blocks: AsyncCreditBlocks) -> None:
+ self._credit_blocks = credit_blocks
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ credit_blocks.retrieve,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ credit_blocks.delete,
+ )
diff --git a/src/orb/resources/invoices.py b/src/orb/resources/invoices.py
index 6ac4f58a..63fa9ab4 100644
--- a/src/orb/resources/invoices.py
+++ b/src/orb/resources/invoices.py
@@ -15,9 +15,10 @@
invoice_create_params,
invoice_update_params,
invoice_mark_paid_params,
+ invoice_list_summary_params,
invoice_fetch_upcoming_params,
)
-from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
from .._utils import maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
@@ -26,6 +27,7 @@
from .._base_client import AsyncPaginator, make_request_options
from ..types.shared.invoice import Invoice
from ..types.shared_params.discount import Discount
+from ..types.invoice_list_summary_response import InvoiceListSummaryResponse
from ..types.invoice_fetch_upcoming_response import InvoiceFetchUpcomingResponse
__all__ = ["Invoices", "AsyncInvoices"]
@@ -322,6 +324,54 @@ def list(
model=Invoice,
)
+ def delete_line_item(
+ self,
+ line_item_id: str,
+ *,
+ invoice_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ idempotency_key: str | None = None,
+ ) -> None:
+ """
+ This endpoint deletes an invoice line item from a draft invoice.
+
+ This endpoint only allows deletion of one-off line items (not subscription-based
+ line items). The invoice must be in a draft status for this operation to
+ succeed.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+
+ idempotency_key: Specify a custom idempotency key for this request
+ """
+ if not invoice_id:
+ raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}")
+ if not line_item_id:
+ raise ValueError(f"Expected a non-empty value for `line_item_id` but received {line_item_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return self._delete(
+ f"/invoices/{invoice_id}/invoice_line_items/{line_item_id}",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=NoneType,
+ )
+
def fetch(
self,
invoice_id: str,
@@ -449,6 +499,108 @@ def issue(
cast_to=Invoice,
)
+ def list_summary(
+ self,
+ *,
+ amount: Optional[str] | Omit = omit,
+ amount_gt: Optional[str] | Omit = omit,
+ amount_lt: Optional[str] | Omit = omit,
+ cursor: Optional[str] | Omit = omit,
+ customer_id: Optional[str] | Omit = omit,
+ date_type: Optional[Literal["due_date", "invoice_date"]] | Omit = omit,
+ due_date: Union[str, date, None] | Omit = omit,
+ due_date_window: Optional[str] | Omit = omit,
+ due_date_gt: Union[str, date, None] | Omit = omit,
+ due_date_lt: Union[str, date, None] | Omit = omit,
+ external_customer_id: Optional[str] | Omit = omit,
+ invoice_date_gt: Union[str, datetime, None] | Omit = omit,
+ invoice_date_gte: Union[str, datetime, None] | Omit = omit,
+ invoice_date_lt: Union[str, datetime, None] | Omit = omit,
+ invoice_date_lte: Union[str, datetime, None] | Omit = omit,
+ is_recurring: Optional[bool] | Omit = omit,
+ limit: int | Omit = omit,
+ status: Optional[Literal["draft", "issued", "paid", "synced", "void"]] | Omit = omit,
+ subscription_id: Optional[str] | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> SyncPage[InvoiceListSummaryResponse]:
+ """
+ This is a lighter-weight endpoint that returns a list of all
+ [`Invoice`](/core-concepts#invoice) summaries for an account in a list format.
+
+ These invoice summaries do not include line item details, minimums, maximums,
+ and discounts, making this endpoint more efficient.
+
+ The list of invoices is ordered starting from the most recently issued invoice
+ date. The response also includes
+ [`pagination_metadata`](/api-reference/pagination), which lets the caller
+ retrieve the next page of results if they exist.
+
+ By default, this only returns invoices that are `issued`, `paid`, or `synced`.
+
+ When fetching any `draft` invoices, this returns the last-computed invoice
+ values for each draft invoice, which may not always be up-to-date since Orb
+ regularly refreshes invoices asynchronously.
+
+ Args:
+ cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned
+ from the initial request.
+
+ due_date_window: Filters invoices by their due dates within a specific time range in the past.
+ Specify the range as a number followed by 'd' (days) or 'm' (months). For
+ example, '7d' filters invoices due in the last 7 days, and '2m' filters those
+ due in the last 2 months.
+
+ limit: The number of items to fetch. Defaults to 20.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
+ "/invoices/summary",
+ page=SyncPage[InvoiceListSummaryResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "amount": amount,
+ "amount_gt": amount_gt,
+ "amount_lt": amount_lt,
+ "cursor": cursor,
+ "customer_id": customer_id,
+ "date_type": date_type,
+ "due_date": due_date,
+ "due_date_window": due_date_window,
+ "due_date_gt": due_date_gt,
+ "due_date_lt": due_date_lt,
+ "external_customer_id": external_customer_id,
+ "invoice_date_gt": invoice_date_gt,
+ "invoice_date_gte": invoice_date_gte,
+ "invoice_date_lt": invoice_date_lt,
+ "invoice_date_lte": invoice_date_lte,
+ "is_recurring": is_recurring,
+ "limit": limit,
+ "status": status,
+ "subscription_id": subscription_id,
+ },
+ invoice_list_summary_params.InvoiceListSummaryParams,
+ ),
+ ),
+ model=InvoiceListSummaryResponse,
+ )
+
def mark_paid(
self,
invoice_id: str,
@@ -892,6 +1044,54 @@ def list(
model=Invoice,
)
+ async def delete_line_item(
+ self,
+ line_item_id: str,
+ *,
+ invoice_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ idempotency_key: str | None = None,
+ ) -> None:
+ """
+ This endpoint deletes an invoice line item from a draft invoice.
+
+ This endpoint only allows deletion of one-off line items (not subscription-based
+ line items). The invoice must be in a draft status for this operation to
+ succeed.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+
+ idempotency_key: Specify a custom idempotency key for this request
+ """
+ if not invoice_id:
+ raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}")
+ if not line_item_id:
+ raise ValueError(f"Expected a non-empty value for `line_item_id` but received {line_item_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return await self._delete(
+ f"/invoices/{invoice_id}/invoice_line_items/{line_item_id}",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=NoneType,
+ )
+
async def fetch(
self,
invoice_id: str,
@@ -1019,6 +1219,108 @@ async def issue(
cast_to=Invoice,
)
+ def list_summary(
+ self,
+ *,
+ amount: Optional[str] | Omit = omit,
+ amount_gt: Optional[str] | Omit = omit,
+ amount_lt: Optional[str] | Omit = omit,
+ cursor: Optional[str] | Omit = omit,
+ customer_id: Optional[str] | Omit = omit,
+ date_type: Optional[Literal["due_date", "invoice_date"]] | Omit = omit,
+ due_date: Union[str, date, None] | Omit = omit,
+ due_date_window: Optional[str] | Omit = omit,
+ due_date_gt: Union[str, date, None] | Omit = omit,
+ due_date_lt: Union[str, date, None] | Omit = omit,
+ external_customer_id: Optional[str] | Omit = omit,
+ invoice_date_gt: Union[str, datetime, None] | Omit = omit,
+ invoice_date_gte: Union[str, datetime, None] | Omit = omit,
+ invoice_date_lt: Union[str, datetime, None] | Omit = omit,
+ invoice_date_lte: Union[str, datetime, None] | Omit = omit,
+ is_recurring: Optional[bool] | Omit = omit,
+ limit: int | Omit = omit,
+ status: Optional[Literal["draft", "issued", "paid", "synced", "void"]] | Omit = omit,
+ subscription_id: Optional[str] | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AsyncPaginator[InvoiceListSummaryResponse, AsyncPage[InvoiceListSummaryResponse]]:
+ """
+ This is a lighter-weight endpoint that returns a list of all
+ [`Invoice`](/core-concepts#invoice) summaries for an account in a list format.
+
+ These invoice summaries do not include line item details, minimums, maximums,
+ and discounts, making this endpoint more efficient.
+
+ The list of invoices is ordered starting from the most recently issued invoice
+ date. The response also includes
+ [`pagination_metadata`](/api-reference/pagination), which lets the caller
+ retrieve the next page of results if they exist.
+
+ By default, this only returns invoices that are `issued`, `paid`, or `synced`.
+
+ When fetching any `draft` invoices, this returns the last-computed invoice
+ values for each draft invoice, which may not always be up-to-date since Orb
+ regularly refreshes invoices asynchronously.
+
+ Args:
+ cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned
+ from the initial request.
+
+ due_date_window: Filters invoices by their due dates within a specific time range in the past.
+ Specify the range as a number followed by 'd' (days) or 'm' (months). For
+ example, '7d' filters invoices due in the last 7 days, and '2m' filters those
+ due in the last 2 months.
+
+ limit: The number of items to fetch. Defaults to 20.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
+ "/invoices/summary",
+ page=AsyncPage[InvoiceListSummaryResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "amount": amount,
+ "amount_gt": amount_gt,
+ "amount_lt": amount_lt,
+ "cursor": cursor,
+ "customer_id": customer_id,
+ "date_type": date_type,
+ "due_date": due_date,
+ "due_date_window": due_date_window,
+ "due_date_gt": due_date_gt,
+ "due_date_lt": due_date_lt,
+ "external_customer_id": external_customer_id,
+ "invoice_date_gt": invoice_date_gt,
+ "invoice_date_gte": invoice_date_gte,
+ "invoice_date_lt": invoice_date_lt,
+ "invoice_date_lte": invoice_date_lte,
+ "is_recurring": is_recurring,
+ "limit": limit,
+ "status": status,
+ "subscription_id": subscription_id,
+ },
+ invoice_list_summary_params.InvoiceListSummaryParams,
+ ),
+ ),
+ model=InvoiceListSummaryResponse,
+ )
+
async def mark_paid(
self,
invoice_id: str,
@@ -1184,6 +1486,9 @@ def __init__(self, invoices: Invoices) -> None:
self.list = _legacy_response.to_raw_response_wrapper(
invoices.list,
)
+ self.delete_line_item = _legacy_response.to_raw_response_wrapper(
+ invoices.delete_line_item,
+ )
self.fetch = _legacy_response.to_raw_response_wrapper(
invoices.fetch,
)
@@ -1193,6 +1498,9 @@ def __init__(self, invoices: Invoices) -> None:
self.issue = _legacy_response.to_raw_response_wrapper(
invoices.issue,
)
+ self.list_summary = _legacy_response.to_raw_response_wrapper(
+ invoices.list_summary,
+ )
self.mark_paid = _legacy_response.to_raw_response_wrapper(
invoices.mark_paid,
)
@@ -1217,6 +1525,9 @@ def __init__(self, invoices: AsyncInvoices) -> None:
self.list = _legacy_response.async_to_raw_response_wrapper(
invoices.list,
)
+ self.delete_line_item = _legacy_response.async_to_raw_response_wrapper(
+ invoices.delete_line_item,
+ )
self.fetch = _legacy_response.async_to_raw_response_wrapper(
invoices.fetch,
)
@@ -1226,6 +1537,9 @@ def __init__(self, invoices: AsyncInvoices) -> None:
self.issue = _legacy_response.async_to_raw_response_wrapper(
invoices.issue,
)
+ self.list_summary = _legacy_response.async_to_raw_response_wrapper(
+ invoices.list_summary,
+ )
self.mark_paid = _legacy_response.async_to_raw_response_wrapper(
invoices.mark_paid,
)
@@ -1250,6 +1564,9 @@ def __init__(self, invoices: Invoices) -> None:
self.list = to_streamed_response_wrapper(
invoices.list,
)
+ self.delete_line_item = to_streamed_response_wrapper(
+ invoices.delete_line_item,
+ )
self.fetch = to_streamed_response_wrapper(
invoices.fetch,
)
@@ -1259,6 +1576,9 @@ def __init__(self, invoices: Invoices) -> None:
self.issue = to_streamed_response_wrapper(
invoices.issue,
)
+ self.list_summary = to_streamed_response_wrapper(
+ invoices.list_summary,
+ )
self.mark_paid = to_streamed_response_wrapper(
invoices.mark_paid,
)
@@ -1283,6 +1603,9 @@ def __init__(self, invoices: AsyncInvoices) -> None:
self.list = async_to_streamed_response_wrapper(
invoices.list,
)
+ self.delete_line_item = async_to_streamed_response_wrapper(
+ invoices.delete_line_item,
+ )
self.fetch = async_to_streamed_response_wrapper(
invoices.fetch,
)
@@ -1292,6 +1615,9 @@ def __init__(self, invoices: AsyncInvoices) -> None:
self.issue = async_to_streamed_response_wrapper(
invoices.issue,
)
+ self.list_summary = async_to_streamed_response_wrapper(
+ invoices.list_summary,
+ )
self.mark_paid = async_to_streamed_response_wrapper(
invoices.mark_paid,
)
diff --git a/src/orb/resources/plans/__init__.py b/src/orb/resources/plans/__init__.py
index fa461833..5af74622 100644
--- a/src/orb/resources/plans/__init__.py
+++ b/src/orb/resources/plans/__init__.py
@@ -8,6 +8,14 @@
PlansWithStreamingResponse,
AsyncPlansWithStreamingResponse,
)
+from .migrations import (
+ Migrations,
+ AsyncMigrations,
+ MigrationsWithRawResponse,
+ AsyncMigrationsWithRawResponse,
+ MigrationsWithStreamingResponse,
+ AsyncMigrationsWithStreamingResponse,
+)
from .external_plan_id import (
ExternalPlanID,
AsyncExternalPlanID,
@@ -24,6 +32,12 @@
"AsyncExternalPlanIDWithRawResponse",
"ExternalPlanIDWithStreamingResponse",
"AsyncExternalPlanIDWithStreamingResponse",
+ "Migrations",
+ "AsyncMigrations",
+ "MigrationsWithRawResponse",
+ "AsyncMigrationsWithRawResponse",
+ "MigrationsWithStreamingResponse",
+ "AsyncMigrationsWithStreamingResponse",
"Plans",
"AsyncPlans",
"PlansWithRawResponse",
diff --git a/src/orb/resources/plans/migrations.py b/src/orb/resources/plans/migrations.py
new file mode 100644
index 00000000..593a7e10
--- /dev/null
+++ b/src/orb/resources/plans/migrations.py
@@ -0,0 +1,392 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+
+import httpx
+
+from ... import _legacy_response
+from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ..._utils import maybe_transform
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ...pagination import SyncPage, AsyncPage
+from ...types.plans import migration_list_params
+from ..._base_client import AsyncPaginator, make_request_options
+from ...types.plans.migration_list_response import MigrationListResponse
+from ...types.plans.migration_cancel_response import MigrationCancelResponse
+from ...types.plans.migration_retrieve_response import MigrationRetrieveResponse
+
+__all__ = ["Migrations", "AsyncMigrations"]
+
+
+class Migrations(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> MigrationsWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers
+ """
+ return MigrationsWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> MigrationsWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response
+ """
+ return MigrationsWithStreamingResponse(self)
+
+ def retrieve(
+ self,
+ migration_id: str,
+ *,
+ plan_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> MigrationRetrieveResponse:
+ """
+ Fetch migration
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not plan_id:
+ raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}")
+ if not migration_id:
+ raise ValueError(f"Expected a non-empty value for `migration_id` but received {migration_id!r}")
+ return self._get(
+ f"/plans/{plan_id}/migrations/{migration_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=MigrationRetrieveResponse,
+ )
+
+ def list(
+ self,
+ plan_id: str,
+ *,
+ cursor: Optional[str] | Omit = omit,
+ limit: int | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> SyncPage[MigrationListResponse]:
+ """This endpoint returns a list of all migrations for a plan.
+
+ The list of
+ migrations is ordered starting from the most recently created migration. The
+ response also includes pagination_metadata, which lets the caller retrieve the
+ next page of results if they exist.
+
+ Args:
+ cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned
+ from the initial request.
+
+ limit: The number of items to fetch. Defaults to 20.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not plan_id:
+ raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}")
+ return self._get_api_list(
+ f"/plans/{plan_id}/migrations",
+ page=SyncPage[MigrationListResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "cursor": cursor,
+ "limit": limit,
+ },
+ migration_list_params.MigrationListParams,
+ ),
+ ),
+ model=MigrationListResponse,
+ )
+
+ def cancel(
+ self,
+ migration_id: str,
+ *,
+ plan_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ idempotency_key: str | None = None,
+ ) -> MigrationCancelResponse:
+ """
+ This endpoint cancels a migration.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+
+ idempotency_key: Specify a custom idempotency key for this request
+ """
+ if not plan_id:
+ raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}")
+ if not migration_id:
+ raise ValueError(f"Expected a non-empty value for `migration_id` but received {migration_id!r}")
+ return self._post(
+ f"/plans/{plan_id}/migrations/{migration_id}/cancel",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=MigrationCancelResponse,
+ )
+
+
+class AsyncMigrations(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncMigrationsWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncMigrationsWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncMigrationsWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response
+ """
+ return AsyncMigrationsWithStreamingResponse(self)
+
+ async def retrieve(
+ self,
+ migration_id: str,
+ *,
+ plan_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> MigrationRetrieveResponse:
+ """
+ Fetch migration
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not plan_id:
+ raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}")
+ if not migration_id:
+ raise ValueError(f"Expected a non-empty value for `migration_id` but received {migration_id!r}")
+ return await self._get(
+ f"/plans/{plan_id}/migrations/{migration_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=MigrationRetrieveResponse,
+ )
+
+ def list(
+ self,
+ plan_id: str,
+ *,
+ cursor: Optional[str] | Omit = omit,
+ limit: int | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AsyncPaginator[MigrationListResponse, AsyncPage[MigrationListResponse]]:
+ """This endpoint returns a list of all migrations for a plan.
+
+ The list of
+ migrations is ordered starting from the most recently created migration. The
+ response also includes pagination_metadata, which lets the caller retrieve the
+ next page of results if they exist.
+
+ Args:
+ cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned
+ from the initial request.
+
+ limit: The number of items to fetch. Defaults to 20.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not plan_id:
+ raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}")
+ return self._get_api_list(
+ f"/plans/{plan_id}/migrations",
+ page=AsyncPage[MigrationListResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "cursor": cursor,
+ "limit": limit,
+ },
+ migration_list_params.MigrationListParams,
+ ),
+ ),
+ model=MigrationListResponse,
+ )
+
+ async def cancel(
+ self,
+ migration_id: str,
+ *,
+ plan_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ idempotency_key: str | None = None,
+ ) -> MigrationCancelResponse:
+ """
+ This endpoint cancels a migration.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+
+ idempotency_key: Specify a custom idempotency key for this request
+ """
+ if not plan_id:
+ raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}")
+ if not migration_id:
+ raise ValueError(f"Expected a non-empty value for `migration_id` but received {migration_id!r}")
+ return await self._post(
+ f"/plans/{plan_id}/migrations/{migration_id}/cancel",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=MigrationCancelResponse,
+ )
+
+
+class MigrationsWithRawResponse:
+ def __init__(self, migrations: Migrations) -> None:
+ self._migrations = migrations
+
+ self.retrieve = _legacy_response.to_raw_response_wrapper(
+ migrations.retrieve,
+ )
+ self.list = _legacy_response.to_raw_response_wrapper(
+ migrations.list,
+ )
+ self.cancel = _legacy_response.to_raw_response_wrapper(
+ migrations.cancel,
+ )
+
+
+class AsyncMigrationsWithRawResponse:
+ def __init__(self, migrations: AsyncMigrations) -> None:
+ self._migrations = migrations
+
+ self.retrieve = _legacy_response.async_to_raw_response_wrapper(
+ migrations.retrieve,
+ )
+ self.list = _legacy_response.async_to_raw_response_wrapper(
+ migrations.list,
+ )
+ self.cancel = _legacy_response.async_to_raw_response_wrapper(
+ migrations.cancel,
+ )
+
+
+class MigrationsWithStreamingResponse:
+ def __init__(self, migrations: Migrations) -> None:
+ self._migrations = migrations
+
+ self.retrieve = to_streamed_response_wrapper(
+ migrations.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ migrations.list,
+ )
+ self.cancel = to_streamed_response_wrapper(
+ migrations.cancel,
+ )
+
+
+class AsyncMigrationsWithStreamingResponse:
+ def __init__(self, migrations: AsyncMigrations) -> None:
+ self._migrations = migrations
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ migrations.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ migrations.list,
+ )
+ self.cancel = async_to_streamed_response_wrapper(
+ migrations.cancel,
+ )
diff --git a/src/orb/resources/plans/plans.py b/src/orb/resources/plans/plans.py
index 257f1774..64d0bad8 100644
--- a/src/orb/resources/plans/plans.py
+++ b/src/orb/resources/plans/plans.py
@@ -13,6 +13,14 @@
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
from ..._utils import maybe_transform, async_maybe_transform
from ..._compat import cached_property
+from .migrations import (
+ Migrations,
+ AsyncMigrations,
+ MigrationsWithRawResponse,
+ AsyncMigrationsWithRawResponse,
+ MigrationsWithStreamingResponse,
+ AsyncMigrationsWithStreamingResponse,
+)
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
from ...pagination import SyncPage, AsyncPage
@@ -35,6 +43,10 @@ class Plans(SyncAPIResource):
def external_plan_id(self) -> ExternalPlanID:
return ExternalPlanID(self._client)
+ @cached_property
+ def migrations(self) -> Migrations:
+ return Migrations(self._client)
+
@cached_property
def with_raw_response(self) -> PlansWithRawResponse:
"""
@@ -320,6 +332,10 @@ class AsyncPlans(AsyncAPIResource):
def external_plan_id(self) -> AsyncExternalPlanID:
return AsyncExternalPlanID(self._client)
+ @cached_property
+ def migrations(self) -> AsyncMigrations:
+ return AsyncMigrations(self._client)
+
@cached_property
def with_raw_response(self) -> AsyncPlansWithRawResponse:
"""
@@ -621,6 +637,10 @@ def __init__(self, plans: Plans) -> None:
def external_plan_id(self) -> ExternalPlanIDWithRawResponse:
return ExternalPlanIDWithRawResponse(self._plans.external_plan_id)
+ @cached_property
+ def migrations(self) -> MigrationsWithRawResponse:
+ return MigrationsWithRawResponse(self._plans.migrations)
+
class AsyncPlansWithRawResponse:
def __init__(self, plans: AsyncPlans) -> None:
@@ -643,6 +663,10 @@ def __init__(self, plans: AsyncPlans) -> None:
def external_plan_id(self) -> AsyncExternalPlanIDWithRawResponse:
return AsyncExternalPlanIDWithRawResponse(self._plans.external_plan_id)
+ @cached_property
+ def migrations(self) -> AsyncMigrationsWithRawResponse:
+ return AsyncMigrationsWithRawResponse(self._plans.migrations)
+
class PlansWithStreamingResponse:
def __init__(self, plans: Plans) -> None:
@@ -665,6 +689,10 @@ def __init__(self, plans: Plans) -> None:
def external_plan_id(self) -> ExternalPlanIDWithStreamingResponse:
return ExternalPlanIDWithStreamingResponse(self._plans.external_plan_id)
+ @cached_property
+ def migrations(self) -> MigrationsWithStreamingResponse:
+ return MigrationsWithStreamingResponse(self._plans.migrations)
+
class AsyncPlansWithStreamingResponse:
def __init__(self, plans: AsyncPlans) -> None:
@@ -686,3 +714,7 @@ def __init__(self, plans: AsyncPlans) -> None:
@cached_property
def external_plan_id(self) -> AsyncExternalPlanIDWithStreamingResponse:
return AsyncExternalPlanIDWithStreamingResponse(self._plans.external_plan_id)
+
+ @cached_property
+ def migrations(self) -> AsyncMigrationsWithStreamingResponse:
+ return AsyncMigrationsWithStreamingResponse(self._plans.migrations)
diff --git a/src/orb/resources/subscription_changes.py b/src/orb/resources/subscription_changes.py
index 0709fa58..5adbb9e3 100644
--- a/src/orb/resources/subscription_changes.py
+++ b/src/orb/resources/subscription_changes.py
@@ -4,17 +4,20 @@
from typing import Union, Optional
from datetime import date
+from typing_extensions import Literal
import httpx
from .. import _legacy_response
-from ..types import subscription_change_apply_params
+from ..types import subscription_change_list_params, subscription_change_apply_params
from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
from .._utils import maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
-from .._base_client import make_request_options
+from ..pagination import SyncPage, AsyncPage
+from .._base_client import AsyncPaginator, make_request_options
+from ..types.subscription_change_list_response import SubscriptionChangeListResponse
from ..types.subscription_change_apply_response import SubscriptionChangeApplyResponse
from ..types.subscription_change_cancel_response import SubscriptionChangeCancelResponse
from ..types.subscription_change_retrieve_response import SubscriptionChangeRetrieveResponse
@@ -85,6 +88,63 @@ def retrieve(
cast_to=SubscriptionChangeRetrieveResponse,
)
+ def list(
+ self,
+ *,
+ cursor: Optional[str] | Omit = omit,
+ customer_id: Optional[str] | Omit = omit,
+ external_customer_id: Optional[str] | Omit = omit,
+ limit: int | Omit = omit,
+ status: Optional[Literal["pending", "applied", "cancelled"]] | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> SyncPage[SubscriptionChangeListResponse]:
+ """This endpoint returns a list of pending subscription changes for a customer.
+
+ Use
+ the [Fetch Subscription Change](fetch-subscription-change) endpoint to retrieve
+ the expected subscription state after the pending change is applied.
+
+ Args:
+ cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned
+ from the initial request.
+
+ limit: The number of items to fetch. Defaults to 20.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
+ "/subscription_changes",
+ page=SyncPage[SubscriptionChangeListResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "cursor": cursor,
+ "customer_id": customer_id,
+ "external_customer_id": external_customer_id,
+ "limit": limit,
+ "status": status,
+ },
+ subscription_change_list_params.SubscriptionChangeListParams,
+ ),
+ ),
+ model=SubscriptionChangeListResponse,
+ )
+
def apply(
self,
subscription_change_id: str,
@@ -272,6 +332,63 @@ async def retrieve(
cast_to=SubscriptionChangeRetrieveResponse,
)
+ def list(
+ self,
+ *,
+ cursor: Optional[str] | Omit = omit,
+ customer_id: Optional[str] | Omit = omit,
+ external_customer_id: Optional[str] | Omit = omit,
+ limit: int | Omit = omit,
+ status: Optional[Literal["pending", "applied", "cancelled"]] | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AsyncPaginator[SubscriptionChangeListResponse, AsyncPage[SubscriptionChangeListResponse]]:
+ """This endpoint returns a list of pending subscription changes for a customer.
+
+ Use
+ the [Fetch Subscription Change](fetch-subscription-change) endpoint to retrieve
+ the expected subscription state after the pending change is applied.
+
+ Args:
+ cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned
+ from the initial request.
+
+ limit: The number of items to fetch. Defaults to 20.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
+ "/subscription_changes",
+ page=AsyncPage[SubscriptionChangeListResponse],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "cursor": cursor,
+ "customer_id": customer_id,
+ "external_customer_id": external_customer_id,
+ "limit": limit,
+ "status": status,
+ },
+ subscription_change_list_params.SubscriptionChangeListParams,
+ ),
+ ),
+ model=SubscriptionChangeListResponse,
+ )
+
async def apply(
self,
subscription_change_id: str,
@@ -403,6 +520,9 @@ def __init__(self, subscription_changes: SubscriptionChanges) -> None:
self.retrieve = _legacy_response.to_raw_response_wrapper(
subscription_changes.retrieve,
)
+ self.list = _legacy_response.to_raw_response_wrapper(
+ subscription_changes.list,
+ )
self.apply = _legacy_response.to_raw_response_wrapper(
subscription_changes.apply,
)
@@ -418,6 +538,9 @@ def __init__(self, subscription_changes: AsyncSubscriptionChanges) -> None:
self.retrieve = _legacy_response.async_to_raw_response_wrapper(
subscription_changes.retrieve,
)
+ self.list = _legacy_response.async_to_raw_response_wrapper(
+ subscription_changes.list,
+ )
self.apply = _legacy_response.async_to_raw_response_wrapper(
subscription_changes.apply,
)
@@ -433,6 +556,9 @@ def __init__(self, subscription_changes: SubscriptionChanges) -> None:
self.retrieve = to_streamed_response_wrapper(
subscription_changes.retrieve,
)
+ self.list = to_streamed_response_wrapper(
+ subscription_changes.list,
+ )
self.apply = to_streamed_response_wrapper(
subscription_changes.apply,
)
@@ -448,6 +574,9 @@ def __init__(self, subscription_changes: AsyncSubscriptionChanges) -> None:
self.retrieve = async_to_streamed_response_wrapper(
subscription_changes.retrieve,
)
+ self.list = async_to_streamed_response_wrapper(
+ subscription_changes.list,
+ )
self.apply = async_to_streamed_response_wrapper(
subscription_changes.apply,
)
diff --git a/src/orb/types/__init__.py b/src/orb/types/__init__.py
index 59ff1e6c..57a93dd5 100644
--- a/src/orb/types/__init__.py
+++ b/src/orb/types/__init__.py
@@ -195,7 +195,10 @@
from .subscription_cancel_params import SubscriptionCancelParams as SubscriptionCancelParams
from .subscription_create_params import SubscriptionCreateParams as SubscriptionCreateParams
from .subscription_update_params import SubscriptionUpdateParams as SubscriptionUpdateParams
+from .invoice_list_summary_params import InvoiceListSummaryParams as InvoiceListSummaryParams
from .invoice_fetch_upcoming_params import InvoiceFetchUpcomingParams as InvoiceFetchUpcomingParams
+from .invoice_list_summary_response import InvoiceListSummaryResponse as InvoiceListSummaryResponse
+from .credit_block_retrieve_response import CreditBlockRetrieveResponse as CreditBlockRetrieveResponse
from .new_sphere_configuration_param import NewSphereConfigurationParam as NewSphereConfigurationParam
from .price_evaluate_multiple_params import PriceEvaluateMultipleParams as PriceEvaluateMultipleParams
from .beta_create_plan_version_params import BetaCreatePlanVersionParams as BetaCreatePlanVersionParams
@@ -203,6 +206,7 @@
from .invoice_fetch_upcoming_response import InvoiceFetchUpcomingResponse as InvoiceFetchUpcomingResponse
from .invoice_line_item_create_params import InvoiceLineItemCreateParams as InvoiceLineItemCreateParams
from .new_tax_jar_configuration_param import NewTaxJarConfigurationParam as NewTaxJarConfigurationParam
+from .subscription_change_list_params import SubscriptionChangeListParams as SubscriptionChangeListParams
from .subscription_fetch_costs_params import SubscriptionFetchCostsParams as SubscriptionFetchCostsParams
from .subscription_fetch_usage_params import SubscriptionFetchUsageParams as SubscriptionFetchUsageParams
from .accounting_provider_config_param import AccountingProviderConfigParam as AccountingProviderConfigParam
@@ -214,6 +218,7 @@
from .new_reporting_configuration_param import NewReportingConfigurationParam as NewReportingConfigurationParam
from .new_subscription_bulk_price_param import NewSubscriptionBulkPriceParam as NewSubscriptionBulkPriceParam
from .new_subscription_unit_price_param import NewSubscriptionUnitPriceParam as NewSubscriptionUnitPriceParam
+from .subscription_change_list_response import SubscriptionChangeListResponse as SubscriptionChangeListResponse
from .subscription_fetch_costs_response import SubscriptionFetchCostsResponse as SubscriptionFetchCostsResponse
from .subscription_redeem_coupon_params import SubscriptionRedeemCouponParams as SubscriptionRedeemCouponParams
from .subscription_trigger_phase_params import SubscriptionTriggerPhaseParams as SubscriptionTriggerPhaseParams
diff --git a/src/orb/types/credit_block_retrieve_response.py b/src/orb/types/credit_block_retrieve_response.py
new file mode 100644
index 00000000..b931d83b
--- /dev/null
+++ b/src/orb/types/credit_block_retrieve_response.py
@@ -0,0 +1,40 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["CreditBlockRetrieveResponse", "Filter"]
+
+
+class Filter(BaseModel):
+ field: Literal["price_id", "item_id", "price_type", "currency", "pricing_unit_id"]
+ """The property of the price to filter on."""
+
+ operator: Literal["includes", "excludes"]
+ """Should prices that match the filter be included or excluded."""
+
+ values: List[str]
+ """The IDs or values that match this filter."""
+
+
+class CreditBlockRetrieveResponse(BaseModel):
+ """The Credit Block resource models prepaid credits within Orb."""
+
+ id: str
+
+ balance: float
+
+ effective_date: Optional[datetime] = None
+
+ expiry_date: Optional[datetime] = None
+
+ filters: List[Filter]
+
+ maximum_initial_balance: Optional[float] = None
+
+ per_unit_cost_basis: Optional[str] = None
+
+ status: Literal["active", "pending_payment"]
diff --git a/src/orb/types/invoice_list_summary_params.py b/src/orb/types/invoice_list_summary_params.py
new file mode 100644
index 00000000..41b86e65
--- /dev/null
+++ b/src/orb/types/invoice_list_summary_params.py
@@ -0,0 +1,63 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Optional
+from datetime import date, datetime
+from typing_extensions import Literal, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["InvoiceListSummaryParams"]
+
+
+class InvoiceListSummaryParams(TypedDict, total=False):
+ amount: Optional[str]
+
+ amount_gt: Annotated[Optional[str], PropertyInfo(alias="amount[gt]")]
+
+ amount_lt: Annotated[Optional[str], PropertyInfo(alias="amount[lt]")]
+
+ cursor: Optional[str]
+ """Cursor for pagination.
+
+ This can be populated by the `next_cursor` value returned from the initial
+ request.
+ """
+
+ customer_id: Optional[str]
+
+ date_type: Optional[Literal["due_date", "invoice_date"]]
+
+ due_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")]
+
+ due_date_window: Optional[str]
+ """Filters invoices by their due dates within a specific time range in the past.
+
+ Specify the range as a number followed by 'd' (days) or 'm' (months). For
+ example, '7d' filters invoices due in the last 7 days, and '2m' filters those
+ due in the last 2 months.
+ """
+
+ due_date_gt: Annotated[Union[str, date, None], PropertyInfo(alias="due_date[gt]", format="iso8601")]
+
+ due_date_lt: Annotated[Union[str, date, None], PropertyInfo(alias="due_date[lt]", format="iso8601")]
+
+ external_customer_id: Optional[str]
+
+ invoice_date_gt: Annotated[Union[str, datetime, None], PropertyInfo(alias="invoice_date[gt]", format="iso8601")]
+
+ invoice_date_gte: Annotated[Union[str, datetime, None], PropertyInfo(alias="invoice_date[gte]", format="iso8601")]
+
+ invoice_date_lt: Annotated[Union[str, datetime, None], PropertyInfo(alias="invoice_date[lt]", format="iso8601")]
+
+ invoice_date_lte: Annotated[Union[str, datetime, None], PropertyInfo(alias="invoice_date[lte]", format="iso8601")]
+
+ is_recurring: Optional[bool]
+
+ limit: int
+ """The number of items to fetch. Defaults to 20."""
+
+ status: Optional[Literal["draft", "issued", "paid", "synced", "void"]]
+
+ subscription_id: Optional[str]
diff --git a/src/orb/types/invoice_list_summary_response.py b/src/orb/types/invoice_list_summary_response.py
new file mode 100644
index 00000000..553979b6
--- /dev/null
+++ b/src/orb/types/invoice_list_summary_response.py
@@ -0,0 +1,425 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+from .shared.address import Address
+from .shared.invoice_tiny import InvoiceTiny
+from .shared.customer_tax_id import CustomerTaxID
+from .shared.credit_note_tiny import CreditNoteTiny
+from .shared.customer_minified import CustomerMinified
+from .shared.subscription_minified import SubscriptionMinified
+
+__all__ = ["InvoiceListSummaryResponse", "AutoCollection", "CreditNote", "CustomerBalanceTransaction", "PaymentAttempt"]
+
+
+class AutoCollection(BaseModel):
+ enabled: Optional[bool] = None
+ """True only if auto-collection is enabled for this invoice."""
+
+ next_attempt_at: Optional[datetime] = None
+ """
+ If the invoice is scheduled for auto-collection, this field will reflect when
+ the next attempt will occur. If dunning has been exhausted, or auto-collection
+ is not enabled for this invoice, this field will be `null`.
+ """
+
+ num_attempts: Optional[int] = None
+ """Number of auto-collection payment attempts."""
+
+ previously_attempted_at: Optional[datetime] = None
+ """
+ If Orb has ever attempted payment auto-collection for this invoice, this field
+ will reflect when that attempt occurred. In conjunction with `next_attempt_at`,
+ this can be used to tell whether the invoice is currently in dunning (that is,
+ `previously_attempted_at` is non-null, and `next_attempt_time` is non-null), or
+ if dunning has been exhausted (`previously_attempted_at` is non-null, but
+ `next_attempt_time` is null).
+ """
+
+
+class CreditNote(BaseModel):
+ id: str
+
+ credit_note_number: str
+
+ memo: Optional[str] = None
+ """An optional memo supplied on the credit note."""
+
+ reason: str
+
+ total: str
+
+ type: str
+
+ voided_at: Optional[datetime] = None
+ """
+ If the credit note has a status of `void`, this gives a timestamp when the
+ credit note was voided.
+ """
+
+
+class CustomerBalanceTransaction(BaseModel):
+ id: str
+ """A unique id for this transaction."""
+
+ action: Literal[
+ "applied_to_invoice",
+ "manual_adjustment",
+ "prorated_refund",
+ "revert_prorated_refund",
+ "return_from_voiding",
+ "credit_note_applied",
+ "credit_note_voided",
+ "overpayment_refund",
+ "external_payment",
+ "small_invoice_carryover",
+ ]
+
+ amount: str
+ """The value of the amount changed in the transaction."""
+
+ created_at: datetime
+ """The creation time of this transaction."""
+
+ credit_note: Optional[CreditNoteTiny] = None
+
+ description: Optional[str] = None
+ """An optional description provided for manual customer balance adjustments."""
+
+ ending_balance: str
+ """
+ The new value of the customer's balance prior to the transaction, in the
+ customer's currency.
+ """
+
+ invoice: Optional[InvoiceTiny] = None
+
+ starting_balance: str
+ """
+ The original value of the customer's balance prior to the transaction, in the
+ customer's currency.
+ """
+
+ type: Literal["increment", "decrement"]
+
+
+class PaymentAttempt(BaseModel):
+ id: str
+ """The ID of the payment attempt."""
+
+ amount: str
+ """The amount of the payment attempt."""
+
+ created_at: datetime
+ """The time at which the payment attempt was created."""
+
+ payment_provider: Optional[Literal["stripe"]] = None
+ """The payment provider that attempted to collect the payment."""
+
+ payment_provider_id: Optional[str] = None
+ """The ID of the payment attempt in the payment provider."""
+
+ receipt_pdf: Optional[str] = None
+ """URL to the downloadable PDF version of the receipt.
+
+ This field will be `null` for payment attempts that did not succeed.
+ """
+
+ succeeded: bool
+ """Whether the payment attempt succeeded."""
+
+
+class InvoiceListSummaryResponse(BaseModel):
+ """#InvoiceApiResourceWithoutLineItems"""
+
+ id: str
+
+ amount_due: str
+ """
+ This is the final amount required to be charged to the customer and reflects the
+ application of the customer balance to the `total` of the invoice.
+ """
+
+ auto_collection: AutoCollection
+
+ billing_address: Optional[Address] = None
+
+ created_at: datetime
+ """The creation time of the resource in Orb."""
+
+ credit_notes: List[CreditNote]
+ """A list of credit notes associated with the invoice"""
+
+ currency: str
+ """An ISO 4217 currency string or `credits`"""
+
+ customer: CustomerMinified
+
+ customer_balance_transactions: List[CustomerBalanceTransaction]
+
+ customer_tax_id: Optional[CustomerTaxID] = None
+ """
+ Tax IDs are commonly required to be displayed on customer invoices, which are
+ added to the headers of invoices.
+
+ ### Supported Tax ID Countries and Types
+
+ | Country | Type | Description |
+ | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------- |
+ | Albania | `al_tin` | Albania Tax Identification Number |
+ | Andorra | `ad_nrt` | Andorran NRT Number |
+ | Angola | `ao_tin` | Angola Tax Identification Number |
+ | Argentina | `ar_cuit` | Argentinian Tax ID Number |
+ | Armenia | `am_tin` | Armenia Tax Identification Number |
+ | Aruba | `aw_tin` | Aruba Tax Identification Number |
+ | Australia | `au_abn` | Australian Business Number (AU ABN) |
+ | Australia | `au_arn` | Australian Taxation Office Reference Number |
+ | Austria | `eu_vat` | European VAT Number |
+ | Azerbaijan | `az_tin` | Azerbaijan Tax Identification Number |
+ | Bahamas | `bs_tin` | Bahamas Tax Identification Number |
+ | Bahrain | `bh_vat` | Bahraini VAT Number |
+ | Bangladesh | `bd_bin` | Bangladesh Business Identification Number |
+ | Barbados | `bb_tin` | Barbados Tax Identification Number |
+ | Belarus | `by_tin` | Belarus TIN Number |
+ | Belgium | `eu_vat` | European VAT Number |
+ | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant Fiscal Unique) |
+ | Bolivia | `bo_tin` | Bolivian Tax ID |
+ | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina Tax Identification Number |
+ | Brazil | `br_cnpj` | Brazilian CNPJ Number |
+ | Brazil | `br_cpf` | Brazilian CPF Number |
+ | Bulgaria | `bg_uic` | Bulgaria Unified Identification Code |
+ | Bulgaria | `eu_vat` | European VAT Number |
+ | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique) |
+ | Cambodia | `kh_tin` | Cambodia Tax Identification Number |
+ | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique) |
+ | Canada | `ca_bn` | Canadian BN |
+ | Canada | `ca_gst_hst` | Canadian GST/HST Number |
+ | Canada | `ca_pst_bc` | Canadian PST Number (British Columbia) |
+ | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) |
+ | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) |
+ | Canada | `ca_qst` | Canadian QST Number (Québec) |
+ | Cape Verde | `cv_nif` | Cape Verde Tax Identification Number (Número de Identificação Fiscal) |
+ | Chile | `cl_tin` | Chilean TIN |
+ | China | `cn_tin` | Chinese Tax ID |
+ | Colombia | `co_nit` | Colombian NIT Number |
+ | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) |
+ | Costa Rica | `cr_tin` | Costa Rican Tax ID |
+ | Croatia | `eu_vat` | European VAT Number |
+ | Croatia | `hr_oib` | Croatian Personal Identification Number (OIB) |
+ | Cyprus | `eu_vat` | European VAT Number |
+ | Czech Republic | `eu_vat` | European VAT Number |
+ | Denmark | `eu_vat` | European VAT Number |
+ | Dominican Republic | `do_rcn` | Dominican RCN Number |
+ | Ecuador | `ec_ruc` | Ecuadorian RUC Number |
+ | Egypt | `eg_tin` | Egyptian Tax Identification Number |
+ | El Salvador | `sv_nit` | El Salvadorian NIT Number |
+ | Estonia | `eu_vat` | European VAT Number |
+ | Ethiopia | `et_tin` | Ethiopia Tax Identification Number |
+ | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union scheme |
+ | Finland | `eu_vat` | European VAT Number |
+ | France | `eu_vat` | European VAT Number |
+ | Georgia | `ge_vat` | Georgian VAT |
+ | Germany | `de_stn` | German Tax Number (Steuernummer) |
+ | Germany | `eu_vat` | European VAT Number |
+ | Greece | `eu_vat` | European VAT Number |
+ | Guinea | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) |
+ | Hong Kong | `hk_br` | Hong Kong BR Number |
+ | Hungary | `eu_vat` | European VAT Number |
+ | Hungary | `hu_tin` | Hungary Tax Number (adószám) |
+ | Iceland | `is_vat` | Icelandic VAT |
+ | India | `in_gst` | Indian GST Number |
+ | Indonesia | `id_npwp` | Indonesian NPWP Number |
+ | Ireland | `eu_vat` | European VAT Number |
+ | Israel | `il_vat` | Israel VAT |
+ | Italy | `eu_vat` | European VAT Number |
+ | Japan | `jp_cn` | Japanese Corporate Number (_Hōjin Bangō_) |
+ | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration Number (_Tōroku Kokugai Jigyōsha no Tōroku Bangō_) |
+ | Japan | `jp_trn` | Japanese Tax Registration Number (_Tōroku Bangō_) |
+ | Kazakhstan | `kz_bin` | Kazakhstani Business Identification Number |
+ | Kenya | `ke_pin` | Kenya Revenue Authority Personal Identification Number |
+ | Kyrgyzstan | `kg_tin` | Kyrgyzstan Tax Identification Number |
+ | Laos | `la_tin` | Laos Tax Identification Number |
+ | Latvia | `eu_vat` | European VAT Number |
+ | Liechtenstein | `li_uid` | Liechtensteinian UID Number |
+ | Liechtenstein | `li_vat` | Liechtenstein VAT Number |
+ | Lithuania | `eu_vat` | European VAT Number |
+ | Luxembourg | `eu_vat` | European VAT Number |
+ | Malaysia | `my_frp` | Malaysian FRP Number |
+ | Malaysia | `my_itn` | Malaysian ITN |
+ | Malaysia | `my_sst` | Malaysian SST Number |
+ | Malta | `eu_vat` | European VAT Number |
+ | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número de Identificação Fiscal) |
+ | Mexico | `mx_rfc` | Mexican RFC Number |
+ | Moldova | `md_vat` | Moldova VAT Number |
+ | Montenegro | `me_pib` | Montenegro PIB Number |
+ | Morocco | `ma_vat` | Morocco VAT Number |
+ | Nepal | `np_pan` | Nepal PAN Number |
+ | Netherlands | `eu_vat` | European VAT Number |
+ | New Zealand | `nz_gst` | New Zealand GST Number |
+ | Nigeria | `ng_tin` | Nigerian Tax Identification Number |
+ | North Macedonia | `mk_vat` | North Macedonia VAT Number |
+ | Northern Ireland | `eu_vat` | Northern Ireland VAT Number |
+ | Norway | `no_vat` | Norwegian VAT Number |
+ | Norway | `no_voec` | Norwegian VAT on e-commerce Number |
+ | Oman | `om_vat` | Omani VAT Number |
+ | Peru | `pe_ruc` | Peruvian RUC Number |
+ | Philippines | `ph_tin` | Philippines Tax Identification Number |
+ | Poland | `eu_vat` | European VAT Number |
+ | Portugal | `eu_vat` | European VAT Number |
+ | Romania | `eu_vat` | European VAT Number |
+ | Romania | `ro_tin` | Romanian Tax ID Number |
+ | Russia | `ru_inn` | Russian INN |
+ | Russia | `ru_kpp` | Russian KPP |
+ | Saudi Arabia | `sa_vat` | Saudi Arabia VAT |
+ | Senegal | `sn_ninea` | Senegal NINEA Number |
+ | Serbia | `rs_pib` | Serbian PIB Number |
+ | Singapore | `sg_gst` | Singaporean GST |
+ | Singapore | `sg_uen` | Singaporean UEN |
+ | Slovakia | `eu_vat` | European VAT Number |
+ | Slovenia | `eu_vat` | European VAT Number |
+ | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) |
+ | South Africa | `za_vat` | South African VAT Number |
+ | South Korea | `kr_brn` | Korean BRN |
+ | Spain | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) |
+ | Spain | `eu_vat` | European VAT Number |
+ | Suriname | `sr_fin` | Suriname FIN Number |
+ | Sweden | `eu_vat` | European VAT Number |
+ | Switzerland | `ch_uid` | Switzerland UID Number |
+ | Switzerland | `ch_vat` | Switzerland VAT Number |
+ | Taiwan | `tw_vat` | Taiwanese VAT |
+ | Tajikistan | `tj_tin` | Tajikistan Tax Identification Number |
+ | Tanzania | `tz_vat` | Tanzania VAT Number |
+ | Thailand | `th_vat` | Thai VAT |
+ | Turkey | `tr_tin` | Turkish Tax Identification Number |
+ | Uganda | `ug_tin` | Uganda Tax Identification Number |
+ | Ukraine | `ua_vat` | Ukrainian VAT |
+ | United Arab Emirates | `ae_trn` | United Arab Emirates TRN |
+ | United Kingdom | `gb_vat` | United Kingdom VAT Number |
+ | United States | `us_ein` | United States EIN |
+ | Uruguay | `uy_ruc` | Uruguayan RUC Number |
+ | Uzbekistan | `uz_tin` | Uzbekistan TIN Number |
+ | Uzbekistan | `uz_vat` | Uzbekistan VAT Number |
+ | Venezuela | `ve_rif` | Venezuelan RIF Number |
+ | Vietnam | `vn_tin` | Vietnamese Tax ID Number |
+ | Zambia | `zm_tin` | Zambia Tax Identification Number |
+ | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number |
+ """
+
+ due_date: Optional[datetime] = None
+ """When the invoice payment is due.
+
+ The due date is null if the invoice is not yet finalized.
+ """
+
+ eligible_to_issue_at: Optional[datetime] = None
+ """
+ If the invoice has a status of `draft`, this will be the time that the invoice
+ will be eligible to be issued, otherwise it will be `null`. If `auto-issue` is
+ true, the invoice will automatically begin issuing at this time.
+ """
+
+ hosted_invoice_url: Optional[str] = None
+ """A URL for the customer-facing invoice portal.
+
+ This URL expires 30 days after the invoice's due date, or 60 days after being
+ re-generated through the UI.
+ """
+
+ invoice_date: datetime
+ """The scheduled date of the invoice"""
+
+ invoice_number: str
+ """Automatically generated invoice number to help track and reconcile invoices.
+
+ Invoice numbers have a prefix such as `RFOBWG`. These can be sequential per
+ account or customer.
+ """
+
+ invoice_pdf: Optional[str] = None
+ """The link to download the PDF representation of the `Invoice`."""
+
+ invoice_source: Literal["subscription", "partial", "one_off"]
+
+ issue_failed_at: Optional[datetime] = None
+ """
+ If the invoice failed to issue, this will be the last time it failed to issue
+ (even if it is now in a different state.)
+ """
+
+ issued_at: Optional[datetime] = None
+ """
+ If the invoice has been issued, this will be the time it transitioned to
+ `issued` (even if it is now in a different state.)
+ """
+
+ memo: Optional[str] = None
+ """
+ Free-form text which is available on the invoice PDF and the Orb invoice portal.
+ """
+
+ metadata: Dict[str, str]
+ """User specified key-value pairs for the resource.
+
+ If not present, this defaults to an empty dictionary. Individual keys can be
+ removed by setting the value to `null`, and the entire metadata mapping can be
+ cleared by setting `metadata` to `null`.
+ """
+
+ paid_at: Optional[datetime] = None
+ """
+ If the invoice has a status of `paid`, this gives a timestamp when the invoice
+ was paid.
+ """
+
+ payment_attempts: List[PaymentAttempt]
+ """A list of payment attempts associated with the invoice"""
+
+ payment_failed_at: Optional[datetime] = None
+ """
+ If payment was attempted on this invoice but failed, this will be the time of
+ the most recent attempt.
+ """
+
+ payment_started_at: Optional[datetime] = None
+ """
+ If payment was attempted on this invoice, this will be the start time of the
+ most recent attempt. This field is especially useful for delayed-notification
+ payment mechanisms (like bank transfers), where payment can take 3 days or more.
+ """
+
+ scheduled_issue_at: Optional[datetime] = None
+ """
+ If the invoice is in draft, this timestamp will reflect when the invoice is
+ scheduled to be issued.
+ """
+
+ shipping_address: Optional[Address] = None
+
+ status: Literal["issued", "paid", "synced", "void", "draft"]
+
+ subscription: Optional[SubscriptionMinified] = None
+
+ sync_failed_at: Optional[datetime] = None
+ """
+ If the invoice failed to sync, this will be the last time an external invoicing
+ provider sync was attempted. This field will always be `null` for invoices using
+ Orb Invoicing.
+ """
+
+ total: str
+ """The total after any minimums and discounts have been applied."""
+
+ voided_at: Optional[datetime] = None
+ """
+ If the invoice has a status of `void`, this gives a timestamp when the invoice
+ was voided.
+ """
+
+ will_auto_issue: bool
+ """
+ This is true if the invoice will be automatically issued in the future, and
+ false otherwise.
+ """
diff --git a/src/orb/types/plans/__init__.py b/src/orb/types/plans/__init__.py
index 6108b59a..37f6dbd3 100644
--- a/src/orb/types/plans/__init__.py
+++ b/src/orb/types/plans/__init__.py
@@ -2,4 +2,8 @@
from __future__ import annotations
+from .migration_list_params import MigrationListParams as MigrationListParams
+from .migration_list_response import MigrationListResponse as MigrationListResponse
+from .migration_cancel_response import MigrationCancelResponse as MigrationCancelResponse
+from .migration_retrieve_response import MigrationRetrieveResponse as MigrationRetrieveResponse
from .external_plan_id_update_params import ExternalPlanIDUpdateParams as ExternalPlanIDUpdateParams
diff --git a/src/orb/types/plans/migration_cancel_response.py b/src/orb/types/plans/migration_cancel_response.py
new file mode 100644
index 00000000..e95010cd
--- /dev/null
+++ b/src/orb/types/plans/migration_cancel_response.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from datetime import date, datetime
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["MigrationCancelResponse"]
+
+
+class MigrationCancelResponse(BaseModel):
+ id: str
+
+ effective_time: Union[date, datetime, Literal["end_of_term"], None] = None
+
+ plan_id: str
+
+ status: Literal["not_started", "in_progress", "completed", "action_needed", "canceled"]
diff --git a/src/orb/types/plans/migration_list_params.py b/src/orb/types/plans/migration_list_params.py
new file mode 100644
index 00000000..aecb3f1d
--- /dev/null
+++ b/src/orb/types/plans/migration_list_params.py
@@ -0,0 +1,20 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import TypedDict
+
+__all__ = ["MigrationListParams"]
+
+
+class MigrationListParams(TypedDict, total=False):
+ cursor: Optional[str]
+ """Cursor for pagination.
+
+ This can be populated by the `next_cursor` value returned from the initial
+ request.
+ """
+
+ limit: int
+ """The number of items to fetch. Defaults to 20."""
diff --git a/src/orb/types/plans/migration_list_response.py b/src/orb/types/plans/migration_list_response.py
new file mode 100644
index 00000000..3ebf0fc7
--- /dev/null
+++ b/src/orb/types/plans/migration_list_response.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from datetime import date, datetime
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["MigrationListResponse"]
+
+
+class MigrationListResponse(BaseModel):
+ id: str
+
+ effective_time: Union[date, datetime, Literal["end_of_term"], None] = None
+
+ plan_id: str
+
+ status: Literal["not_started", "in_progress", "completed", "action_needed", "canceled"]
diff --git a/src/orb/types/plans/migration_retrieve_response.py b/src/orb/types/plans/migration_retrieve_response.py
new file mode 100644
index 00000000..aed370c0
--- /dev/null
+++ b/src/orb/types/plans/migration_retrieve_response.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from datetime import date, datetime
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["MigrationRetrieveResponse"]
+
+
+class MigrationRetrieveResponse(BaseModel):
+ id: str
+
+ effective_time: Union[date, datetime, Literal["end_of_term"], None] = None
+
+ plan_id: str
+
+ status: Literal["not_started", "in_progress", "completed", "action_needed", "canceled"]
diff --git a/src/orb/types/subscription_change_list_params.py b/src/orb/types/subscription_change_list_params.py
new file mode 100644
index 00000000..3d52e7ab
--- /dev/null
+++ b/src/orb/types/subscription_change_list_params.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, TypedDict
+
+__all__ = ["SubscriptionChangeListParams"]
+
+
+class SubscriptionChangeListParams(TypedDict, total=False):
+ cursor: Optional[str]
+ """Cursor for pagination.
+
+ This can be populated by the `next_cursor` value returned from the initial
+ request.
+ """
+
+ customer_id: Optional[str]
+
+ external_customer_id: Optional[str]
+
+ limit: int
+ """The number of items to fetch. Defaults to 20."""
+
+ status: Optional[Literal["pending", "applied", "cancelled"]]
diff --git a/src/orb/types/subscription_change_list_response.py b/src/orb/types/subscription_change_list_response.py
new file mode 100644
index 00000000..1a706ddf
--- /dev/null
+++ b/src/orb/types/subscription_change_list_response.py
@@ -0,0 +1,28 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["SubscriptionChangeListResponse"]
+
+
+class SubscriptionChangeListResponse(BaseModel):
+ id: str
+
+ expiration_time: datetime
+ """
+ Subscription change will be cancelled at this time and can no longer be applied.
+ """
+
+ status: Literal["pending", "applied", "cancelled"]
+
+ subscription_id: Optional[str] = None
+
+ applied_at: Optional[datetime] = None
+ """When this change was applied."""
+
+ cancelled_at: Optional[datetime] = None
+ """When this change was cancelled."""
diff --git a/tests/api_resources/plans/test_migrations.py b/tests/api_resources/plans/test_migrations.py
new file mode 100644
index 00000000..d680314d
--- /dev/null
+++ b/tests/api_resources/plans/test_migrations.py
@@ -0,0 +1,315 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from orb import Orb, AsyncOrb
+from tests.utils import assert_matches_type
+from orb.pagination import SyncPage, AsyncPage
+from orb.types.plans import (
+ MigrationListResponse,
+ MigrationCancelResponse,
+ MigrationRetrieveResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestMigrations:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_retrieve(self, client: Orb) -> None:
+ migration = client.plans.migrations.retrieve(
+ migration_id="migration_id",
+ plan_id="plan_id",
+ )
+ assert_matches_type(MigrationRetrieveResponse, migration, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Orb) -> None:
+ response = client.plans.migrations.with_raw_response.retrieve(
+ migration_id="migration_id",
+ plan_id="plan_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ migration = response.parse()
+ assert_matches_type(MigrationRetrieveResponse, migration, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Orb) -> None:
+ with client.plans.migrations.with_streaming_response.retrieve(
+ migration_id="migration_id",
+ plan_id="plan_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ migration = response.parse()
+ assert_matches_type(MigrationRetrieveResponse, migration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: Orb) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"):
+ client.plans.migrations.with_raw_response.retrieve(
+ migration_id="migration_id",
+ plan_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `migration_id` but received ''"):
+ client.plans.migrations.with_raw_response.retrieve(
+ migration_id="",
+ plan_id="plan_id",
+ )
+
+ @parametrize
+ def test_method_list(self, client: Orb) -> None:
+ migration = client.plans.migrations.list(
+ plan_id="plan_id",
+ )
+ assert_matches_type(SyncPage[MigrationListResponse], migration, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Orb) -> None:
+ migration = client.plans.migrations.list(
+ plan_id="plan_id",
+ cursor="cursor",
+ limit=1,
+ )
+ assert_matches_type(SyncPage[MigrationListResponse], migration, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Orb) -> None:
+ response = client.plans.migrations.with_raw_response.list(
+ plan_id="plan_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ migration = response.parse()
+ assert_matches_type(SyncPage[MigrationListResponse], migration, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Orb) -> None:
+ with client.plans.migrations.with_streaming_response.list(
+ plan_id="plan_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ migration = response.parse()
+ assert_matches_type(SyncPage[MigrationListResponse], migration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_list(self, client: Orb) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"):
+ client.plans.migrations.with_raw_response.list(
+ plan_id="",
+ )
+
+ @parametrize
+ def test_method_cancel(self, client: Orb) -> None:
+ migration = client.plans.migrations.cancel(
+ migration_id="migration_id",
+ plan_id="plan_id",
+ )
+ assert_matches_type(MigrationCancelResponse, migration, path=["response"])
+
+ @parametrize
+ def test_raw_response_cancel(self, client: Orb) -> None:
+ response = client.plans.migrations.with_raw_response.cancel(
+ migration_id="migration_id",
+ plan_id="plan_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ migration = response.parse()
+ assert_matches_type(MigrationCancelResponse, migration, path=["response"])
+
+ @parametrize
+ def test_streaming_response_cancel(self, client: Orb) -> None:
+ with client.plans.migrations.with_streaming_response.cancel(
+ migration_id="migration_id",
+ plan_id="plan_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ migration = response.parse()
+ assert_matches_type(MigrationCancelResponse, migration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_cancel(self, client: Orb) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"):
+ client.plans.migrations.with_raw_response.cancel(
+ migration_id="migration_id",
+ plan_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `migration_id` but received ''"):
+ client.plans.migrations.with_raw_response.cancel(
+ migration_id="",
+ plan_id="plan_id",
+ )
+
+
+class TestAsyncMigrations:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncOrb) -> None:
+ migration = await async_client.plans.migrations.retrieve(
+ migration_id="migration_id",
+ plan_id="plan_id",
+ )
+ assert_matches_type(MigrationRetrieveResponse, migration, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncOrb) -> None:
+ response = await async_client.plans.migrations.with_raw_response.retrieve(
+ migration_id="migration_id",
+ plan_id="plan_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ migration = response.parse()
+ assert_matches_type(MigrationRetrieveResponse, migration, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncOrb) -> None:
+ async with async_client.plans.migrations.with_streaming_response.retrieve(
+ migration_id="migration_id",
+ plan_id="plan_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ migration = await response.parse()
+ assert_matches_type(MigrationRetrieveResponse, migration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncOrb) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"):
+ await async_client.plans.migrations.with_raw_response.retrieve(
+ migration_id="migration_id",
+ plan_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `migration_id` but received ''"):
+ await async_client.plans.migrations.with_raw_response.retrieve(
+ migration_id="",
+ plan_id="plan_id",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncOrb) -> None:
+ migration = await async_client.plans.migrations.list(
+ plan_id="plan_id",
+ )
+ assert_matches_type(AsyncPage[MigrationListResponse], migration, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None:
+ migration = await async_client.plans.migrations.list(
+ plan_id="plan_id",
+ cursor="cursor",
+ limit=1,
+ )
+ assert_matches_type(AsyncPage[MigrationListResponse], migration, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncOrb) -> None:
+ response = await async_client.plans.migrations.with_raw_response.list(
+ plan_id="plan_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ migration = response.parse()
+ assert_matches_type(AsyncPage[MigrationListResponse], migration, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None:
+ async with async_client.plans.migrations.with_streaming_response.list(
+ plan_id="plan_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ migration = await response.parse()
+ assert_matches_type(AsyncPage[MigrationListResponse], migration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_list(self, async_client: AsyncOrb) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"):
+ await async_client.plans.migrations.with_raw_response.list(
+ plan_id="",
+ )
+
+ @parametrize
+ async def test_method_cancel(self, async_client: AsyncOrb) -> None:
+ migration = await async_client.plans.migrations.cancel(
+ migration_id="migration_id",
+ plan_id="plan_id",
+ )
+ assert_matches_type(MigrationCancelResponse, migration, path=["response"])
+
+ @parametrize
+ async def test_raw_response_cancel(self, async_client: AsyncOrb) -> None:
+ response = await async_client.plans.migrations.with_raw_response.cancel(
+ migration_id="migration_id",
+ plan_id="plan_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ migration = response.parse()
+ assert_matches_type(MigrationCancelResponse, migration, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_cancel(self, async_client: AsyncOrb) -> None:
+ async with async_client.plans.migrations.with_streaming_response.cancel(
+ migration_id="migration_id",
+ plan_id="plan_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ migration = await response.parse()
+ assert_matches_type(MigrationCancelResponse, migration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_cancel(self, async_client: AsyncOrb) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"):
+ await async_client.plans.migrations.with_raw_response.cancel(
+ migration_id="migration_id",
+ plan_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `migration_id` but received ''"):
+ await async_client.plans.migrations.with_raw_response.cancel(
+ migration_id="",
+ plan_id="plan_id",
+ )
diff --git a/tests/api_resources/test_credit_blocks.py b/tests/api_resources/test_credit_blocks.py
new file mode 100644
index 00000000..1d5f30ae
--- /dev/null
+++ b/tests/api_resources/test_credit_blocks.py
@@ -0,0 +1,176 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from orb import Orb, AsyncOrb
+from orb.types import CreditBlockRetrieveResponse
+from tests.utils import assert_matches_type
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestCreditBlocks:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_retrieve(self, client: Orb) -> None:
+ credit_block = client.credit_blocks.retrieve(
+ "block_id",
+ )
+ assert_matches_type(CreditBlockRetrieveResponse, credit_block, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Orb) -> None:
+ response = client.credit_blocks.with_raw_response.retrieve(
+ "block_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ credit_block = response.parse()
+ assert_matches_type(CreditBlockRetrieveResponse, credit_block, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Orb) -> None:
+ with client.credit_blocks.with_streaming_response.retrieve(
+ "block_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ credit_block = response.parse()
+ assert_matches_type(CreditBlockRetrieveResponse, credit_block, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: Orb) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `block_id` but received ''"):
+ client.credit_blocks.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ def test_method_delete(self, client: Orb) -> None:
+ credit_block = client.credit_blocks.delete(
+ "block_id",
+ )
+ assert credit_block is None
+
+ @parametrize
+ def test_raw_response_delete(self, client: Orb) -> None:
+ response = client.credit_blocks.with_raw_response.delete(
+ "block_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ credit_block = response.parse()
+ assert credit_block is None
+
+ @parametrize
+ def test_streaming_response_delete(self, client: Orb) -> None:
+ with client.credit_blocks.with_streaming_response.delete(
+ "block_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ credit_block = response.parse()
+ assert credit_block is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_delete(self, client: Orb) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `block_id` but received ''"):
+ client.credit_blocks.with_raw_response.delete(
+ "",
+ )
+
+
+class TestAsyncCreditBlocks:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncOrb) -> None:
+ credit_block = await async_client.credit_blocks.retrieve(
+ "block_id",
+ )
+ assert_matches_type(CreditBlockRetrieveResponse, credit_block, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncOrb) -> None:
+ response = await async_client.credit_blocks.with_raw_response.retrieve(
+ "block_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ credit_block = response.parse()
+ assert_matches_type(CreditBlockRetrieveResponse, credit_block, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncOrb) -> None:
+ async with async_client.credit_blocks.with_streaming_response.retrieve(
+ "block_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ credit_block = await response.parse()
+ assert_matches_type(CreditBlockRetrieveResponse, credit_block, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncOrb) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `block_id` but received ''"):
+ await async_client.credit_blocks.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncOrb) -> None:
+ credit_block = await async_client.credit_blocks.delete(
+ "block_id",
+ )
+ assert credit_block is None
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncOrb) -> None:
+ response = await async_client.credit_blocks.with_raw_response.delete(
+ "block_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ credit_block = response.parse()
+ assert credit_block is None
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncOrb) -> None:
+ async with async_client.credit_blocks.with_streaming_response.delete(
+ "block_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ credit_block = await response.parse()
+ assert credit_block is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_delete(self, async_client: AsyncOrb) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `block_id` but received ''"):
+ await async_client.credit_blocks.with_raw_response.delete(
+ "",
+ )
diff --git a/tests/api_resources/test_invoices.py b/tests/api_resources/test_invoices.py
index db64ecc2..38ef17ea 100644
--- a/tests/api_resources/test_invoices.py
+++ b/tests/api_resources/test_invoices.py
@@ -9,6 +9,7 @@
from orb import Orb, AsyncOrb
from orb.types import (
+ InvoiceListSummaryResponse,
InvoiceFetchUpcomingResponse,
)
from orb._utils import parse_date, parse_datetime
@@ -230,6 +231,54 @@ def test_streaming_response_list(self, client: Orb) -> None:
assert cast(Any, response.is_closed) is True
+ @parametrize
+ def test_method_delete_line_item(self, client: Orb) -> None:
+ invoice = client.invoices.delete_line_item(
+ line_item_id="line_item_id",
+ invoice_id="invoice_id",
+ )
+ assert invoice is None
+
+ @parametrize
+ def test_raw_response_delete_line_item(self, client: Orb) -> None:
+ response = client.invoices.with_raw_response.delete_line_item(
+ line_item_id="line_item_id",
+ invoice_id="invoice_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ invoice = response.parse()
+ assert invoice is None
+
+ @parametrize
+ def test_streaming_response_delete_line_item(self, client: Orb) -> None:
+ with client.invoices.with_streaming_response.delete_line_item(
+ line_item_id="line_item_id",
+ invoice_id="invoice_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ invoice = response.parse()
+ assert invoice is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_delete_line_item(self, client: Orb) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `invoice_id` but received ''"):
+ client.invoices.with_raw_response.delete_line_item(
+ line_item_id="line_item_id",
+ invoice_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `line_item_id` but received ''"):
+ client.invoices.with_raw_response.delete_line_item(
+ line_item_id="",
+ invoice_id="invoice_id",
+ )
+
@parametrize
def test_method_fetch(self, client: Orb) -> None:
invoice = client.invoices.fetch(
@@ -345,6 +394,56 @@ def test_path_params_issue(self, client: Orb) -> None:
invoice_id="",
)
+ @parametrize
+ def test_method_list_summary(self, client: Orb) -> None:
+ invoice = client.invoices.list_summary()
+ assert_matches_type(SyncPage[InvoiceListSummaryResponse], invoice, path=["response"])
+
+ @parametrize
+ def test_method_list_summary_with_all_params(self, client: Orb) -> None:
+ invoice = client.invoices.list_summary(
+ amount="amount",
+ amount_gt="amount[gt]",
+ amount_lt="amount[lt]",
+ cursor="cursor",
+ customer_id="customer_id",
+ date_type="due_date",
+ due_date=parse_date("2019-12-27"),
+ due_date_window="due_date_window",
+ due_date_gt=parse_date("2019-12-27"),
+ due_date_lt=parse_date("2019-12-27"),
+ external_customer_id="external_customer_id",
+ invoice_date_gt=parse_datetime("2019-12-27T18:11:19.117Z"),
+ invoice_date_gte=parse_datetime("2019-12-27T18:11:19.117Z"),
+ invoice_date_lt=parse_datetime("2019-12-27T18:11:19.117Z"),
+ invoice_date_lte=parse_datetime("2019-12-27T18:11:19.117Z"),
+ is_recurring=True,
+ limit=1,
+ status="draft",
+ subscription_id="subscription_id",
+ )
+ assert_matches_type(SyncPage[InvoiceListSummaryResponse], invoice, path=["response"])
+
+ @parametrize
+ def test_raw_response_list_summary(self, client: Orb) -> None:
+ response = client.invoices.with_raw_response.list_summary()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ invoice = response.parse()
+ assert_matches_type(SyncPage[InvoiceListSummaryResponse], invoice, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list_summary(self, client: Orb) -> None:
+ with client.invoices.with_streaming_response.list_summary() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ invoice = response.parse()
+ assert_matches_type(SyncPage[InvoiceListSummaryResponse], invoice, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@parametrize
def test_method_mark_paid(self, client: Orb) -> None:
invoice = client.invoices.mark_paid(
@@ -687,6 +786,54 @@ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None:
assert cast(Any, response.is_closed) is True
+ @parametrize
+ async def test_method_delete_line_item(self, async_client: AsyncOrb) -> None:
+ invoice = await async_client.invoices.delete_line_item(
+ line_item_id="line_item_id",
+ invoice_id="invoice_id",
+ )
+ assert invoice is None
+
+ @parametrize
+ async def test_raw_response_delete_line_item(self, async_client: AsyncOrb) -> None:
+ response = await async_client.invoices.with_raw_response.delete_line_item(
+ line_item_id="line_item_id",
+ invoice_id="invoice_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ invoice = response.parse()
+ assert invoice is None
+
+ @parametrize
+ async def test_streaming_response_delete_line_item(self, async_client: AsyncOrb) -> None:
+ async with async_client.invoices.with_streaming_response.delete_line_item(
+ line_item_id="line_item_id",
+ invoice_id="invoice_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ invoice = await response.parse()
+ assert invoice is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_delete_line_item(self, async_client: AsyncOrb) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `invoice_id` but received ''"):
+ await async_client.invoices.with_raw_response.delete_line_item(
+ line_item_id="line_item_id",
+ invoice_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `line_item_id` but received ''"):
+ await async_client.invoices.with_raw_response.delete_line_item(
+ line_item_id="",
+ invoice_id="invoice_id",
+ )
+
@parametrize
async def test_method_fetch(self, async_client: AsyncOrb) -> None:
invoice = await async_client.invoices.fetch(
@@ -802,6 +949,56 @@ async def test_path_params_issue(self, async_client: AsyncOrb) -> None:
invoice_id="",
)
+ @parametrize
+ async def test_method_list_summary(self, async_client: AsyncOrb) -> None:
+ invoice = await async_client.invoices.list_summary()
+ assert_matches_type(AsyncPage[InvoiceListSummaryResponse], invoice, path=["response"])
+
+ @parametrize
+ async def test_method_list_summary_with_all_params(self, async_client: AsyncOrb) -> None:
+ invoice = await async_client.invoices.list_summary(
+ amount="amount",
+ amount_gt="amount[gt]",
+ amount_lt="amount[lt]",
+ cursor="cursor",
+ customer_id="customer_id",
+ date_type="due_date",
+ due_date=parse_date("2019-12-27"),
+ due_date_window="due_date_window",
+ due_date_gt=parse_date("2019-12-27"),
+ due_date_lt=parse_date("2019-12-27"),
+ external_customer_id="external_customer_id",
+ invoice_date_gt=parse_datetime("2019-12-27T18:11:19.117Z"),
+ invoice_date_gte=parse_datetime("2019-12-27T18:11:19.117Z"),
+ invoice_date_lt=parse_datetime("2019-12-27T18:11:19.117Z"),
+ invoice_date_lte=parse_datetime("2019-12-27T18:11:19.117Z"),
+ is_recurring=True,
+ limit=1,
+ status="draft",
+ subscription_id="subscription_id",
+ )
+ assert_matches_type(AsyncPage[InvoiceListSummaryResponse], invoice, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list_summary(self, async_client: AsyncOrb) -> None:
+ response = await async_client.invoices.with_raw_response.list_summary()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ invoice = response.parse()
+ assert_matches_type(AsyncPage[InvoiceListSummaryResponse], invoice, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list_summary(self, async_client: AsyncOrb) -> None:
+ async with async_client.invoices.with_streaming_response.list_summary() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ invoice = await response.parse()
+ assert_matches_type(AsyncPage[InvoiceListSummaryResponse], invoice, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@parametrize
async def test_method_mark_paid(self, async_client: AsyncOrb) -> None:
invoice = await async_client.invoices.mark_paid(
diff --git a/tests/api_resources/test_subscription_changes.py b/tests/api_resources/test_subscription_changes.py
index 5b6fc868..0a5d6dae 100644
--- a/tests/api_resources/test_subscription_changes.py
+++ b/tests/api_resources/test_subscription_changes.py
@@ -9,12 +9,14 @@
from orb import Orb, AsyncOrb
from orb.types import (
+ SubscriptionChangeListResponse,
SubscriptionChangeApplyResponse,
SubscriptionChangeCancelResponse,
SubscriptionChangeRetrieveResponse,
)
from orb._utils import parse_date
from tests.utils import assert_matches_type
+from orb.pagination import SyncPage, AsyncPage
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -62,6 +64,42 @@ def test_path_params_retrieve(self, client: Orb) -> None:
"",
)
+ @parametrize
+ def test_method_list(self, client: Orb) -> None:
+ subscription_change = client.subscription_changes.list()
+ assert_matches_type(SyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Orb) -> None:
+ subscription_change = client.subscription_changes.list(
+ cursor="cursor",
+ customer_id="customer_id",
+ external_customer_id="external_customer_id",
+ limit=1,
+ status="pending",
+ )
+ assert_matches_type(SyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Orb) -> None:
+ response = client.subscription_changes.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ subscription_change = response.parse()
+ assert_matches_type(SyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Orb) -> None:
+ with client.subscription_changes.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ subscription_change = response.parse()
+ assert_matches_type(SyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@parametrize
def test_method_apply(self, client: Orb) -> None:
subscription_change = client.subscription_changes.apply(
@@ -201,6 +239,42 @@ async def test_path_params_retrieve(self, async_client: AsyncOrb) -> None:
"",
)
+ @parametrize
+ async def test_method_list(self, async_client: AsyncOrb) -> None:
+ subscription_change = await async_client.subscription_changes.list()
+ assert_matches_type(AsyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None:
+ subscription_change = await async_client.subscription_changes.list(
+ cursor="cursor",
+ customer_id="customer_id",
+ external_customer_id="external_customer_id",
+ limit=1,
+ status="pending",
+ )
+ assert_matches_type(AsyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncOrb) -> None:
+ response = await async_client.subscription_changes.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ subscription_change = response.parse()
+ assert_matches_type(AsyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncOrb) -> None:
+ async with async_client.subscription_changes.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ subscription_change = await response.parse()
+ assert_matches_type(AsyncPage[SubscriptionChangeListResponse], subscription_change, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@parametrize
async def test_method_apply(self, async_client: AsyncOrb) -> None:
subscription_change = await async_client.subscription_changes.apply(