diff --git a/.stats.yml b/.stats.yml
index 3114caa3..e670c774 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
-configured_endpoints: 96
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-1345a8e288e34d5477b0e189877225f83939a59078c22fbb5367712e376c5d19.yml
+configured_endpoints: 97
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-bf3e71b33372f4a9307f4b6cb689ea46b3cf583ecc5d79eee9601cd0b0467c9a.yml
diff --git a/api.md b/api.md
index 366c8f9e..89f33f14 100644
--- a/api.md
+++ b/api.md
@@ -241,6 +241,7 @@ Methods:
- client.invoices.fetch_upcoming(\*\*params) -> InvoiceFetchUpcomingResponse
- client.invoices.issue(invoice_id, \*\*params) -> Invoice
- client.invoices.mark_paid(invoice_id, \*\*params) -> Invoice
+- client.invoices.pay(invoice_id) -> Invoice
- client.invoices.void(invoice_id) -> Invoice
# Items
diff --git a/src/orb/resources/invoices.py b/src/orb/resources/invoices.py
index ca4c14c2..a85c4c11 100644
--- a/src/orb/resources/invoices.py
+++ b/src/orb/resources/invoices.py
@@ -475,6 +475,47 @@ def mark_paid(
cast_to=Invoice,
)
+ def pay(
+ self,
+ 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,
+ ) -> Invoice:
+ """
+ This endpoint collects payment for an invoice using the customer's default
+ payment method. This action can only be taken on invoices with status "issued".
+
+ 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}")
+ return self._post(
+ f"/invoices/{invoice_id}/pay",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=Invoice,
+ )
+
def void(
self,
invoice_id: str,
@@ -964,6 +1005,47 @@ async def mark_paid(
cast_to=Invoice,
)
+ async def pay(
+ self,
+ 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,
+ ) -> Invoice:
+ """
+ This endpoint collects payment for an invoice using the customer's default
+ payment method. This action can only be taken on invoices with status "issued".
+
+ 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}")
+ return await self._post(
+ f"/invoices/{invoice_id}/pay",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=Invoice,
+ )
+
async def void(
self,
invoice_id: str,
@@ -1037,6 +1119,9 @@ def __init__(self, invoices: Invoices) -> None:
self.mark_paid = _legacy_response.to_raw_response_wrapper(
invoices.mark_paid,
)
+ self.pay = _legacy_response.to_raw_response_wrapper(
+ invoices.pay,
+ )
self.void = _legacy_response.to_raw_response_wrapper(
invoices.void,
)
@@ -1067,6 +1152,9 @@ def __init__(self, invoices: AsyncInvoices) -> None:
self.mark_paid = _legacy_response.async_to_raw_response_wrapper(
invoices.mark_paid,
)
+ self.pay = _legacy_response.async_to_raw_response_wrapper(
+ invoices.pay,
+ )
self.void = _legacy_response.async_to_raw_response_wrapper(
invoices.void,
)
@@ -1097,6 +1185,9 @@ def __init__(self, invoices: Invoices) -> None:
self.mark_paid = to_streamed_response_wrapper(
invoices.mark_paid,
)
+ self.pay = to_streamed_response_wrapper(
+ invoices.pay,
+ )
self.void = to_streamed_response_wrapper(
invoices.void,
)
@@ -1127,6 +1218,9 @@ def __init__(self, invoices: AsyncInvoices) -> None:
self.mark_paid = async_to_streamed_response_wrapper(
invoices.mark_paid,
)
+ self.pay = async_to_streamed_response_wrapper(
+ invoices.pay,
+ )
self.void = async_to_streamed_response_wrapper(
invoices.void,
)
diff --git a/src/orb/types/invoice.py b/src/orb/types/invoice.py
index 23c1786b..964e0f7d 100644
--- a/src/orb/types/invoice.py
+++ b/src/orb/types/invoice.py
@@ -35,6 +35,7 @@
"LineItemTaxAmount",
"Maximum",
"Minimum",
+ "PaymentAttempt",
"ShippingAddress",
"Subscription",
]
@@ -744,6 +745,26 @@ class Minimum(BaseModel):
"""Minimum amount applied"""
+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."""
+
+ succeeded: bool
+ """Whether the payment attempt succeeded."""
+
+
class ShippingAddress(BaseModel):
city: Optional[str] = None
@@ -980,6 +1001,9 @@ class Invoice(BaseModel):
was paid.
"""
+ payment_attempts: List[PaymentAttempt]
+ """A list of payment attempts associated with the invoice"""
+
payment_failed_at: Optional[datetime] = None
"""
If payment was attempted on this invoice but failed, this will be the time of
diff --git a/src/orb/types/invoice_fetch_upcoming_response.py b/src/orb/types/invoice_fetch_upcoming_response.py
index 443aeab9..8ec2e987 100644
--- a/src/orb/types/invoice_fetch_upcoming_response.py
+++ b/src/orb/types/invoice_fetch_upcoming_response.py
@@ -35,6 +35,7 @@
"LineItemTaxAmount",
"Maximum",
"Minimum",
+ "PaymentAttempt",
"ShippingAddress",
"Subscription",
]
@@ -744,6 +745,26 @@ class Minimum(BaseModel):
"""Minimum amount applied"""
+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."""
+
+ succeeded: bool
+ """Whether the payment attempt succeeded."""
+
+
class ShippingAddress(BaseModel):
city: Optional[str] = None
@@ -977,6 +998,9 @@ class InvoiceFetchUpcomingResponse(BaseModel):
was paid.
"""
+ payment_attempts: List[PaymentAttempt]
+ """A list of payment attempts associated with the invoice"""
+
payment_failed_at: Optional[datetime] = None
"""
If payment was attempted on this invoice but failed, this will be the time of
diff --git a/tests/api_resources/test_invoices.py b/tests/api_resources/test_invoices.py
index b38553c5..e95f3a25 100644
--- a/tests/api_resources/test_invoices.py
+++ b/tests/api_resources/test_invoices.py
@@ -386,6 +386,44 @@ def test_path_params_mark_paid(self, client: Orb) -> None:
payment_received_date=parse_date("2023-09-22"),
)
+ @parametrize
+ def test_method_pay(self, client: Orb) -> None:
+ invoice = client.invoices.pay(
+ "invoice_id",
+ )
+ assert_matches_type(Invoice, invoice, path=["response"])
+
+ @parametrize
+ def test_raw_response_pay(self, client: Orb) -> None:
+ response = client.invoices.with_raw_response.pay(
+ "invoice_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ invoice = response.parse()
+ assert_matches_type(Invoice, invoice, path=["response"])
+
+ @parametrize
+ def test_streaming_response_pay(self, client: Orb) -> None:
+ with client.invoices.with_streaming_response.pay(
+ "invoice_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ invoice = response.parse()
+ assert_matches_type(Invoice, invoice, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_pay(self, client: Orb) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `invoice_id` but received ''"):
+ client.invoices.with_raw_response.pay(
+ "",
+ )
+
@parametrize
def test_method_void(self, client: Orb) -> None:
invoice = client.invoices.void(
@@ -792,6 +830,44 @@ async def test_path_params_mark_paid(self, async_client: AsyncOrb) -> None:
payment_received_date=parse_date("2023-09-22"),
)
+ @parametrize
+ async def test_method_pay(self, async_client: AsyncOrb) -> None:
+ invoice = await async_client.invoices.pay(
+ "invoice_id",
+ )
+ assert_matches_type(Invoice, invoice, path=["response"])
+
+ @parametrize
+ async def test_raw_response_pay(self, async_client: AsyncOrb) -> None:
+ response = await async_client.invoices.with_raw_response.pay(
+ "invoice_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ invoice = response.parse()
+ assert_matches_type(Invoice, invoice, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_pay(self, async_client: AsyncOrb) -> None:
+ async with async_client.invoices.with_streaming_response.pay(
+ "invoice_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ invoice = await response.parse()
+ assert_matches_type(Invoice, invoice, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_pay(self, async_client: AsyncOrb) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `invoice_id` but received ''"):
+ await async_client.invoices.with_raw_response.pay(
+ "",
+ )
+
@parametrize
async def test_method_void(self, async_client: AsyncOrb) -> None:
invoice = await async_client.invoices.void(