diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index d3dc9f51..988e843f 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.115.0"
+ ".": "0.116.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index fd0cb7e8..31a62cc4 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 176
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-c24eebe942f400bff8922a6fbef1ce551ad14f61eb4da21b50d823a62ca42586.yml
-openapi_spec_hash: b79ed927e625dedff69cea29131a34d9
-config_hash: 693dddc4721eef512d75ab6c60897794
+configured_endpoints: 184
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-a45946df228eec554b3cd2491f658bd5a45cb91509da0a9f92d50468ea88072f.yml
+openapi_spec_hash: 24c7c13e1e7385cab5442ca66091ffc6
+config_hash: 50031f78031362c2e4900222b9ce7ada
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 981334cd..9bbf5ae5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,34 @@
# Changelog
+## 0.116.0 (2026-02-27)
+
+Full Changelog: [v0.115.0...v0.116.0](https://github.com/lithic-com/lithic-python/compare/v0.115.0...v0.116.0)
+
+### Features
+
+* **api:** Add account holder entity endpoints ([710c501](https://github.com/lithic-com/lithic-python/commit/710c501c3695a51743437488769f1132578c23dd))
+* **api:** Add INTEREST_AND_FEES_PAUSED substatus to financial account ([c4a37de](https://github.com/lithic-com/lithic-python/commit/c4a37de9f0f7821e54d05702c4d1d809124fc7bc))
+* **api:** Expose MIL interest schedules and loan tape configuration endpoints ([5c6bcd7](https://github.com/lithic-com/lithic-python/commit/5c6bcd740933255291c0fd0b482021c4a50d0e78))
+
+
+### Bug Fixes
+
+* **api:** Correct token_metadata field name in tokenization.approval_request schema ([36532d8](https://github.com/lithic-com/lithic-python/commit/36532d836f7cd3ef23b6c70194cd50f9495644ec))
+
+
+### Chores
+
+* **dependencies:** require standardwebhooks 1.0.1 ([7dae789](https://github.com/lithic-com/lithic-python/commit/7dae7892de61a765ab4bca8c7af3046d90fe2ff4))
+* **internal:** add request options to SSE classes ([1b49e55](https://github.com/lithic-com/lithic-python/commit/1b49e550b0e6fe3c5203740a9634ee6264046489))
+* **internal:** make `test_proxy_environment_variables` more resilient ([e12df38](https://github.com/lithic-com/lithic-python/commit/e12df381dda14514d7bc8ce5f7fe7ea882d0fb0f))
+* **internal:** make `test_proxy_environment_variables` more resilient to env ([9d0e878](https://github.com/lithic-com/lithic-python/commit/9d0e87814e2369c791ee5b9f8a4431c9de38e505))
+* update mock server docs ([ec268b7](https://github.com/lithic-com/lithic-python/commit/ec268b7426be15578b2eaf92ca81107cbf9084e6))
+
+
+### Documentation
+
+* Remove CONDITIONAL_BLOCK from docs ([f202486](https://github.com/lithic-com/lithic-python/commit/f202486f3cb2c60338be8d38f09eb23e82acf1ae))
+
## 0.115.0 (2026-02-13)
Full Changelog: [v0.114.0...v0.115.0](https://github.com/lithic-com/lithic-python/compare/v0.114.0...v0.115.0)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d68a8975..e758caa0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -88,8 +88,7 @@ $ pip install ./path-to-wheel-file.whl
Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests.
```sh
-# you will need npm installed
-$ npx prism mock path/to/your/openapi.yml
+$ ./scripts/mock
```
```sh
diff --git a/api.md b/api.md
index 92414f8a..81c83721 100644
--- a/api.md
+++ b/api.md
@@ -63,15 +63,28 @@ from lithic.types import (
Methods:
-- client.account_holders.create(\*\*params) -> AccountHolderCreateResponse
-- client.account_holders.retrieve(account_holder_token) -> AccountHolder
-- client.account_holders.update(account_holder_token, \*\*params) -> AccountHolderUpdateResponse
-- client.account_holders.list(\*\*params) -> SyncSinglePage[AccountHolder]
-- client.account_holders.list_documents(account_holder_token) -> AccountHolderListDocumentsResponse
-- client.account_holders.retrieve_document(document_token, \*, account_holder_token) -> Document
-- client.account_holders.simulate_enrollment_document_review(\*\*params) -> Document
-- client.account_holders.simulate_enrollment_review(\*\*params) -> AccountHolderSimulateEnrollmentReviewResponse
-- client.account_holders.upload_document(account_holder_token, \*\*params) -> Document
+- client.account_holders.create(\*\*params) -> AccountHolderCreateResponse
+- client.account_holders.retrieve(account_holder_token) -> AccountHolder
+- client.account_holders.update(account_holder_token, \*\*params) -> AccountHolderUpdateResponse
+- client.account_holders.list(\*\*params) -> SyncSinglePage[AccountHolder]
+- client.account_holders.list_documents(account_holder_token) -> AccountHolderListDocumentsResponse
+- client.account_holders.retrieve_document(document_token, \*, account_holder_token) -> Document
+- client.account_holders.simulate_enrollment_document_review(\*\*params) -> Document
+- client.account_holders.simulate_enrollment_review(\*\*params) -> AccountHolderSimulateEnrollmentReviewResponse
+- client.account_holders.upload_document(account_holder_token, \*\*params) -> Document
+
+## Entities
+
+Types:
+
+```python
+from lithic.types.account_holders import AccountHolderEntity, EntityCreateResponse
+```
+
+Methods:
+
+- client.account_holders.entities.create(account_holder_token, \*\*params) -> EntityCreateResponse
+- client.account_holders.entities.delete(entity_token, \*, account_holder_token) -> AccountHolderEntity
# AuthRules
@@ -161,7 +174,7 @@ Types:
```python
from lithic.types import (
Device,
- DigitalWalletTokenMetadata,
+ TokenMetadata,
Tokenization,
TokenizationDeclineReason,
TokenizationRuleResult,
@@ -420,6 +433,34 @@ Methods:
- client.financial_accounts.loan_tapes.retrieve(loan_tape_token, \*, financial_account_token) -> LoanTape
- client.financial_accounts.loan_tapes.list(financial_account_token, \*\*params) -> SyncCursorPage[LoanTape]
+## LoanTapeConfiguration
+
+Types:
+
+```python
+from lithic.types.financial_accounts import LoanTapeConfiguration, LoanTapeRebuildConfiguration
+```
+
+Methods:
+
+- client.financial_accounts.loan_tape_configuration.retrieve(financial_account_token) -> LoanTapeConfiguration
+
+## InterestTierSchedule
+
+Types:
+
+```python
+from lithic.types.financial_accounts import CategoryTier, InterestTierSchedule
+```
+
+Methods:
+
+- client.financial_accounts.interest_tier_schedule.create(financial_account_token, \*\*params) -> InterestTierSchedule
+- client.financial_accounts.interest_tier_schedule.retrieve(effective_date, \*, financial_account_token) -> InterestTierSchedule
+- client.financial_accounts.interest_tier_schedule.update(effective_date, \*, financial_account_token, \*\*params) -> InterestTierSchedule
+- client.financial_accounts.interest_tier_schedule.list(financial_account_token, \*\*params) -> SyncSinglePage[InterestTierSchedule]
+- client.financial_accounts.interest_tier_schedule.delete(effective_date, \*, financial_account_token) -> None
+
# Transactions
Types:
diff --git a/pyproject.toml b/pyproject.toml
index 5f325713..18c9a87e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "lithic"
-version = "0.115.0"
+version = "0.116.0"
description = "The official Python library for the lithic API"
dynamic = ["readme"]
license = "Apache-2.0"
@@ -42,7 +42,7 @@ Repository = "https://github.com/lithic-com/lithic-python"
[project.optional-dependencies]
aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.9"]
-webhooks = ["standardwebhooks"]
+webhooks = ["standardwebhooks >= 1.0.1, < 2"]
[tool.rye]
managed = true
diff --git a/requirements-dev.lock b/requirements-dev.lock
index 197f41b6..61575831 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -125,7 +125,7 @@ six==1.17.0
# via python-dateutil
sniffio==1.3.1
# via lithic
-standardwebhooks==1.0.0
+standardwebhooks==1.0.1
# via lithic
time-machine==2.19.0
tomli==2.4.0
diff --git a/requirements.lock b/requirements.lock
index 01e8660f..3ae4c2cf 100644
--- a/requirements.lock
+++ b/requirements.lock
@@ -69,7 +69,7 @@ six==1.17.0
# via python-dateutil
sniffio==1.3.1
# via lithic
-standardwebhooks==1.0.0
+standardwebhooks==1.0.1
# via lithic
types-deprecated==1.3.1.20251101
# via standardwebhooks
diff --git a/src/lithic/_client.py b/src/lithic/_client.py
index 3dd30033..4f9fd51a 100644
--- a/src/lithic/_client.py
+++ b/src/lithic/_client.py
@@ -82,7 +82,6 @@
from .resources.tokenizations import Tokenizations, AsyncTokenizations
from .resources.book_transfers import BookTransfers, AsyncBookTransfers
from .resources.funding_events import FundingEvents, AsyncFundingEvents
- from .resources.account_holders import AccountHolders, AsyncAccountHolders
from .resources.reports.reports import Reports, AsyncReports
from .resources.transfer_limits import TransferLimits, AsyncTransferLimits
from .resources.account_activity import AccountActivity, AsyncAccountActivity
@@ -97,6 +96,7 @@
from .resources.auth_stream_enrollment import AuthStreamEnrollment, AsyncAuthStreamEnrollment
from .resources.tokenization_decisioning import TokenizationDecisioning, AsyncTokenizationDecisioning
from .resources.transactions.transactions import Transactions, AsyncTransactions
+ from .resources.account_holders.account_holders import AccountHolders, AsyncAccountHolders
from .resources.credit_products.credit_products import CreditProducts, AsyncCreditProducts
from .resources.financial_accounts.financial_accounts import FinancialAccounts, AsyncFinancialAccounts
from .resources.external_bank_accounts.external_bank_accounts import ExternalBankAccounts, AsyncExternalBankAccounts
diff --git a/src/lithic/_legacy_response.py b/src/lithic/_legacy_response.py
index d3758f2b..415c593c 100644
--- a/src/lithic/_legacy_response.py
+++ b/src/lithic/_legacy_response.py
@@ -214,6 +214,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
),
response=self.http_response,
client=cast(Any, self._client),
+ options=self._options,
),
)
@@ -224,6 +225,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
cast_to=extract_stream_chunk_type(self._stream_cls),
response=self.http_response,
client=cast(Any, self._client),
+ options=self._options,
),
)
@@ -237,6 +239,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
cast_to=cast_to,
response=self.http_response,
client=cast(Any, self._client),
+ options=self._options,
),
)
diff --git a/src/lithic/_response.py b/src/lithic/_response.py
index 083b08df..f19ac6bc 100644
--- a/src/lithic/_response.py
+++ b/src/lithic/_response.py
@@ -152,6 +152,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
),
response=self.http_response,
client=cast(Any, self._client),
+ options=self._options,
),
)
@@ -162,6 +163,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
cast_to=extract_stream_chunk_type(self._stream_cls),
response=self.http_response,
client=cast(Any, self._client),
+ options=self._options,
),
)
@@ -175,6 +177,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
cast_to=cast_to,
response=self.http_response,
client=cast(Any, self._client),
+ options=self._options,
),
)
diff --git a/src/lithic/_streaming.py b/src/lithic/_streaming.py
index 73afbbec..38d8cb5f 100644
--- a/src/lithic/_streaming.py
+++ b/src/lithic/_streaming.py
@@ -4,7 +4,7 @@
import json
import inspect
from types import TracebackType
-from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, AsyncIterator, cast
+from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, Optional, AsyncIterator, cast
from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable
import httpx
@@ -13,6 +13,7 @@
if TYPE_CHECKING:
from ._client import Lithic, AsyncLithic
+ from ._models import FinalRequestOptions
_T = TypeVar("_T")
@@ -22,7 +23,7 @@ class Stream(Generic[_T]):
"""Provides the core interface to iterate over a synchronous stream response."""
response: httpx.Response
-
+ _options: Optional[FinalRequestOptions] = None
_decoder: SSEBytesDecoder
def __init__(
@@ -31,10 +32,12 @@ def __init__(
cast_to: type[_T],
response: httpx.Response,
client: Lithic,
+ options: Optional[FinalRequestOptions] = None,
) -> None:
self.response = response
self._cast_to = cast_to
self._client = client
+ self._options = options
self._decoder = client._make_sse_decoder()
self._iterator = self.__stream__()
@@ -85,7 +88,7 @@ class AsyncStream(Generic[_T]):
"""Provides the core interface to iterate over an asynchronous stream response."""
response: httpx.Response
-
+ _options: Optional[FinalRequestOptions] = None
_decoder: SSEDecoder | SSEBytesDecoder
def __init__(
@@ -94,10 +97,12 @@ def __init__(
cast_to: type[_T],
response: httpx.Response,
client: AsyncLithic,
+ options: Optional[FinalRequestOptions] = None,
) -> None:
self.response = response
self._cast_to = cast_to
self._client = client
+ self._options = options
self._decoder = client._make_sse_decoder()
self._iterator = self.__stream__()
diff --git a/src/lithic/_version.py b/src/lithic/_version.py
index 9b480c33..d7f6788a 100644
--- a/src/lithic/_version.py
+++ b/src/lithic/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "lithic"
-__version__ = "0.115.0" # x-release-please-version
+__version__ = "0.116.0" # x-release-please-version
diff --git a/src/lithic/resources/account_holders/__init__.py b/src/lithic/resources/account_holders/__init__.py
new file mode 100644
index 00000000..583bc2e8
--- /dev/null
+++ b/src/lithic/resources/account_holders/__init__.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .entities import (
+ Entities,
+ AsyncEntities,
+ EntitiesWithRawResponse,
+ AsyncEntitiesWithRawResponse,
+ EntitiesWithStreamingResponse,
+ AsyncEntitiesWithStreamingResponse,
+)
+from .account_holders import (
+ AccountHolders,
+ AsyncAccountHolders,
+ AccountHoldersWithRawResponse,
+ AsyncAccountHoldersWithRawResponse,
+ AccountHoldersWithStreamingResponse,
+ AsyncAccountHoldersWithStreamingResponse,
+)
+
+__all__ = [
+ "Entities",
+ "AsyncEntities",
+ "EntitiesWithRawResponse",
+ "AsyncEntitiesWithRawResponse",
+ "EntitiesWithStreamingResponse",
+ "AsyncEntitiesWithStreamingResponse",
+ "AccountHolders",
+ "AsyncAccountHolders",
+ "AccountHoldersWithRawResponse",
+ "AsyncAccountHoldersWithRawResponse",
+ "AccountHoldersWithStreamingResponse",
+ "AsyncAccountHoldersWithStreamingResponse",
+]
diff --git a/src/lithic/resources/account_holders.py b/src/lithic/resources/account_holders/account_holders.py
similarity index 98%
rename from src/lithic/resources/account_holders.py
rename to src/lithic/resources/account_holders/account_holders.py
index b4440f72..ee283367 100644
--- a/src/lithic/resources/account_holders.py
+++ b/src/lithic/resources/account_holders/account_holders.py
@@ -8,8 +8,8 @@
import httpx
-from .. import _legacy_response
-from ..types import (
+from ... import _legacy_response
+from ...types import (
account_holder_list_params,
account_holder_create_params,
account_holder_update_params,
@@ -17,27 +17,39 @@
account_holder_simulate_enrollment_review_params,
account_holder_simulate_enrollment_document_review_params,
)
-from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
-from .._utils import is_given, required_args, 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 .._constants import DEFAULT_TIMEOUT
-from ..pagination import SyncSinglePage, AsyncSinglePage
-from .._base_client import AsyncPaginator, make_request_options
-from ..types.account_holder import AccountHolder
-from ..types.shared.document import Document
-from ..types.address_update_param import AddressUpdateParam
-from ..types.shared_params.address import Address
-from ..types.account_holder_create_response import AccountHolderCreateResponse
-from ..types.account_holder_update_response import AccountHolderUpdateResponse
-from ..types.account_holder_list_documents_response import AccountHolderListDocumentsResponse
-from ..types.account_holder_simulate_enrollment_review_response import AccountHolderSimulateEnrollmentReviewResponse
+from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
+from ..._utils import is_given, required_args, maybe_transform, async_maybe_transform
+from .entities import (
+ Entities,
+ AsyncEntities,
+ EntitiesWithRawResponse,
+ AsyncEntitiesWithRawResponse,
+ EntitiesWithStreamingResponse,
+ AsyncEntitiesWithStreamingResponse,
+)
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ..._constants import DEFAULT_TIMEOUT
+from ...pagination import SyncSinglePage, AsyncSinglePage
+from ..._base_client import AsyncPaginator, make_request_options
+from ...types.account_holder import AccountHolder
+from ...types.shared.document import Document
+from ...types.address_update_param import AddressUpdateParam
+from ...types.shared_params.address import Address
+from ...types.account_holder_create_response import AccountHolderCreateResponse
+from ...types.account_holder_update_response import AccountHolderUpdateResponse
+from ...types.account_holder_list_documents_response import AccountHolderListDocumentsResponse
+from ...types.account_holder_simulate_enrollment_review_response import AccountHolderSimulateEnrollmentReviewResponse
__all__ = ["AccountHolders", "AsyncAccountHolders"]
class AccountHolders(SyncAPIResource):
+ @cached_property
+ def entities(self) -> Entities:
+ return Entities(self._client)
+
@cached_property
def with_raw_response(self) -> AccountHoldersWithRawResponse:
"""
@@ -1124,6 +1136,10 @@ def upload_document(
class AsyncAccountHolders(AsyncAPIResource):
+ @cached_property
+ def entities(self) -> AsyncEntities:
+ return AsyncEntities(self._client)
+
@cached_property
def with_raw_response(self) -> AsyncAccountHoldersWithRawResponse:
"""
@@ -2241,6 +2257,10 @@ def __init__(self, account_holders: AccountHolders) -> None:
account_holders.upload_document,
)
+ @cached_property
+ def entities(self) -> EntitiesWithRawResponse:
+ return EntitiesWithRawResponse(self._account_holders.entities)
+
class AsyncAccountHoldersWithRawResponse:
def __init__(self, account_holders: AsyncAccountHolders) -> None:
@@ -2274,6 +2294,10 @@ def __init__(self, account_holders: AsyncAccountHolders) -> None:
account_holders.upload_document,
)
+ @cached_property
+ def entities(self) -> AsyncEntitiesWithRawResponse:
+ return AsyncEntitiesWithRawResponse(self._account_holders.entities)
+
class AccountHoldersWithStreamingResponse:
def __init__(self, account_holders: AccountHolders) -> None:
@@ -2307,6 +2331,10 @@ def __init__(self, account_holders: AccountHolders) -> None:
account_holders.upload_document,
)
+ @cached_property
+ def entities(self) -> EntitiesWithStreamingResponse:
+ return EntitiesWithStreamingResponse(self._account_holders.entities)
+
class AsyncAccountHoldersWithStreamingResponse:
def __init__(self, account_holders: AsyncAccountHolders) -> None:
@@ -2339,3 +2367,7 @@ def __init__(self, account_holders: AsyncAccountHolders) -> None:
self.upload_document = async_to_streamed_response_wrapper(
account_holders.upload_document,
)
+
+ @cached_property
+ def entities(self) -> AsyncEntitiesWithStreamingResponse:
+ return AsyncEntitiesWithStreamingResponse(self._account_holders.entities)
diff --git a/src/lithic/resources/account_holders/entities.py b/src/lithic/resources/account_holders/entities.py
new file mode 100644
index 00000000..ebc307b6
--- /dev/null
+++ b/src/lithic/resources/account_holders/entities.py
@@ -0,0 +1,352 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal
+
+import httpx
+
+from ... import _legacy_response
+from ..._types import Body, Query, Headers, NotGiven, 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 ...types.account_holders import entity_create_params
+from ...types.account_holders.account_holder_entity import AccountHolderEntity
+from ...types.account_holders.entity_create_response import EntityCreateResponse
+
+__all__ = ["Entities", "AsyncEntities"]
+
+
+class Entities(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> EntitiesWithRawResponse:
+ """
+ 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/lithic-com/lithic-python#accessing-raw-response-data-eg-headers
+ """
+ return EntitiesWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> EntitiesWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/lithic-com/lithic-python#with_streaming_response
+ """
+ return EntitiesWithStreamingResponse(self)
+
+ def create(
+ self,
+ account_holder_token: str,
+ *,
+ address: entity_create_params.Address,
+ dob: str,
+ email: str,
+ first_name: str,
+ government_id: str,
+ last_name: str,
+ phone_number: str,
+ type: Literal["BENEFICIAL_OWNER_INDIVIDUAL", "CONTROL_PERSON"],
+ # 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,
+ ) -> EntityCreateResponse:
+ """
+ Create a new beneficial owner or replace the control person entity on an
+ existing KYB account holder. This endpoint is only applicable for account
+ holders enrolled through a KYB workflow with the Persona KYB provider. A new
+ control person can only replace the existing one. A maximum of 4 beneficial
+ owners can be associated with an account holder.
+
+ Args:
+ address: Individual's current address - PO boxes, UPS drops, and FedEx drops are not
+ acceptable; APO/FPO are acceptable. Only USA addresses are currently supported.
+
+ dob: Individual's date of birth, as an RFC 3339 date.
+
+ email: Individual's email address. If utilizing Lithic for chargeback processing, this
+ customer email address may be used to communicate dispute status and resolution.
+
+ first_name: Individual's first name, as it appears on government-issued identity documents.
+
+ government_id: Government-issued identification number (required for identity verification and
+ compliance with banking regulations). Social Security Numbers (SSN) and
+ Individual Taxpayer Identification Numbers (ITIN) are currently supported,
+ entered as full nine-digits, with or without hyphens
+
+ last_name: Individual's last name, as it appears on government-issued identity documents.
+
+ phone_number: Individual's phone number, entered in E.164 format.
+
+ type: The type of entity to create on the account holder
+
+ 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 account_holder_token:
+ raise ValueError(
+ f"Expected a non-empty value for `account_holder_token` but received {account_holder_token!r}"
+ )
+ return self._post(
+ f"/v1/account_holders/{account_holder_token}/entities",
+ body=maybe_transform(
+ {
+ "address": address,
+ "dob": dob,
+ "email": email,
+ "first_name": first_name,
+ "government_id": government_id,
+ "last_name": last_name,
+ "phone_number": phone_number,
+ "type": type,
+ },
+ entity_create_params.EntityCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=EntityCreateResponse,
+ )
+
+ def delete(
+ self,
+ entity_token: str,
+ *,
+ account_holder_token: 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,
+ ) -> AccountHolderEntity:
+ """Deactivate a beneficial owner entity on an existing KYB account holder.
+
+ Only
+ beneficial owner entities can be deactivated.
+
+ 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 account_holder_token:
+ raise ValueError(
+ f"Expected a non-empty value for `account_holder_token` but received {account_holder_token!r}"
+ )
+ if not entity_token:
+ raise ValueError(f"Expected a non-empty value for `entity_token` but received {entity_token!r}")
+ return self._delete(
+ f"/v1/account_holders/{account_holder_token}/entities/{entity_token}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AccountHolderEntity,
+ )
+
+
+class AsyncEntities(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncEntitiesWithRawResponse:
+ """
+ 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/lithic-com/lithic-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncEntitiesWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncEntitiesWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/lithic-com/lithic-python#with_streaming_response
+ """
+ return AsyncEntitiesWithStreamingResponse(self)
+
+ async def create(
+ self,
+ account_holder_token: str,
+ *,
+ address: entity_create_params.Address,
+ dob: str,
+ email: str,
+ first_name: str,
+ government_id: str,
+ last_name: str,
+ phone_number: str,
+ type: Literal["BENEFICIAL_OWNER_INDIVIDUAL", "CONTROL_PERSON"],
+ # 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,
+ ) -> EntityCreateResponse:
+ """
+ Create a new beneficial owner or replace the control person entity on an
+ existing KYB account holder. This endpoint is only applicable for account
+ holders enrolled through a KYB workflow with the Persona KYB provider. A new
+ control person can only replace the existing one. A maximum of 4 beneficial
+ owners can be associated with an account holder.
+
+ Args:
+ address: Individual's current address - PO boxes, UPS drops, and FedEx drops are not
+ acceptable; APO/FPO are acceptable. Only USA addresses are currently supported.
+
+ dob: Individual's date of birth, as an RFC 3339 date.
+
+ email: Individual's email address. If utilizing Lithic for chargeback processing, this
+ customer email address may be used to communicate dispute status and resolution.
+
+ first_name: Individual's first name, as it appears on government-issued identity documents.
+
+ government_id: Government-issued identification number (required for identity verification and
+ compliance with banking regulations). Social Security Numbers (SSN) and
+ Individual Taxpayer Identification Numbers (ITIN) are currently supported,
+ entered as full nine-digits, with or without hyphens
+
+ last_name: Individual's last name, as it appears on government-issued identity documents.
+
+ phone_number: Individual's phone number, entered in E.164 format.
+
+ type: The type of entity to create on the account holder
+
+ 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 account_holder_token:
+ raise ValueError(
+ f"Expected a non-empty value for `account_holder_token` but received {account_holder_token!r}"
+ )
+ return await self._post(
+ f"/v1/account_holders/{account_holder_token}/entities",
+ body=await async_maybe_transform(
+ {
+ "address": address,
+ "dob": dob,
+ "email": email,
+ "first_name": first_name,
+ "government_id": government_id,
+ "last_name": last_name,
+ "phone_number": phone_number,
+ "type": type,
+ },
+ entity_create_params.EntityCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=EntityCreateResponse,
+ )
+
+ async def delete(
+ self,
+ entity_token: str,
+ *,
+ account_holder_token: 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,
+ ) -> AccountHolderEntity:
+ """Deactivate a beneficial owner entity on an existing KYB account holder.
+
+ Only
+ beneficial owner entities can be deactivated.
+
+ 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 account_holder_token:
+ raise ValueError(
+ f"Expected a non-empty value for `account_holder_token` but received {account_holder_token!r}"
+ )
+ if not entity_token:
+ raise ValueError(f"Expected a non-empty value for `entity_token` but received {entity_token!r}")
+ return await self._delete(
+ f"/v1/account_holders/{account_holder_token}/entities/{entity_token}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AccountHolderEntity,
+ )
+
+
+class EntitiesWithRawResponse:
+ def __init__(self, entities: Entities) -> None:
+ self._entities = entities
+
+ self.create = _legacy_response.to_raw_response_wrapper(
+ entities.create,
+ )
+ self.delete = _legacy_response.to_raw_response_wrapper(
+ entities.delete,
+ )
+
+
+class AsyncEntitiesWithRawResponse:
+ def __init__(self, entities: AsyncEntities) -> None:
+ self._entities = entities
+
+ self.create = _legacy_response.async_to_raw_response_wrapper(
+ entities.create,
+ )
+ self.delete = _legacy_response.async_to_raw_response_wrapper(
+ entities.delete,
+ )
+
+
+class EntitiesWithStreamingResponse:
+ def __init__(self, entities: Entities) -> None:
+ self._entities = entities
+
+ self.create = to_streamed_response_wrapper(
+ entities.create,
+ )
+ self.delete = to_streamed_response_wrapper(
+ entities.delete,
+ )
+
+
+class AsyncEntitiesWithStreamingResponse:
+ def __init__(self, entities: AsyncEntities) -> None:
+ self._entities = entities
+
+ self.create = async_to_streamed_response_wrapper(
+ entities.create,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ entities.delete,
+ )
diff --git a/src/lithic/resources/auth_rules/v2/v2.py b/src/lithic/resources/auth_rules/v2/v2.py
index 6a212e97..5e207bb1 100644
--- a/src/lithic/resources/auth_rules/v2/v2.py
+++ b/src/lithic/resources/auth_rules/v2/v2.py
@@ -95,7 +95,8 @@ def create(
several event streams, the effective one is defined by the separate
`event_stream` field.
- - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream.
+ - `CONDITIONAL_BLOCK`: Deprecated. Use `CONDITIONAL_ACTION` instead.
+ AUTHORIZATION event stream.
- `VELOCITY_LIMIT`: AUTHORIZATION event stream.
- `MERCHANT_LOCK`: AUTHORIZATION event stream.
- `CONDITIONAL_ACTION`: AUTHORIZATION, THREE_DS_AUTHENTICATION, TOKENIZATION,
@@ -148,7 +149,8 @@ def create(
several event streams, the effective one is defined by the separate
`event_stream` field.
- - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream.
+ - `CONDITIONAL_BLOCK`: Deprecated. Use `CONDITIONAL_ACTION` instead.
+ AUTHORIZATION event stream.
- `VELOCITY_LIMIT`: AUTHORIZATION event stream.
- `MERCHANT_LOCK`: AUTHORIZATION event stream.
- `CONDITIONAL_ACTION`: AUTHORIZATION, THREE_DS_AUTHENTICATION, TOKENIZATION,
@@ -198,7 +200,8 @@ def create(
several event streams, the effective one is defined by the separate
`event_stream` field.
- - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream.
+ - `CONDITIONAL_BLOCK`: Deprecated. Use `CONDITIONAL_ACTION` instead.
+ AUTHORIZATION event stream.
- `VELOCITY_LIMIT`: AUTHORIZATION event stream.
- `MERCHANT_LOCK`: AUTHORIZATION event stream.
- `CONDITIONAL_ACTION`: AUTHORIZATION, THREE_DS_AUTHENTICATION, TOKENIZATION,
@@ -900,7 +903,8 @@ async def create(
several event streams, the effective one is defined by the separate
`event_stream` field.
- - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream.
+ - `CONDITIONAL_BLOCK`: Deprecated. Use `CONDITIONAL_ACTION` instead.
+ AUTHORIZATION event stream.
- `VELOCITY_LIMIT`: AUTHORIZATION event stream.
- `MERCHANT_LOCK`: AUTHORIZATION event stream.
- `CONDITIONAL_ACTION`: AUTHORIZATION, THREE_DS_AUTHENTICATION, TOKENIZATION,
@@ -953,7 +957,8 @@ async def create(
several event streams, the effective one is defined by the separate
`event_stream` field.
- - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream.
+ - `CONDITIONAL_BLOCK`: Deprecated. Use `CONDITIONAL_ACTION` instead.
+ AUTHORIZATION event stream.
- `VELOCITY_LIMIT`: AUTHORIZATION event stream.
- `MERCHANT_LOCK`: AUTHORIZATION event stream.
- `CONDITIONAL_ACTION`: AUTHORIZATION, THREE_DS_AUTHENTICATION, TOKENIZATION,
@@ -1003,7 +1008,8 @@ async def create(
several event streams, the effective one is defined by the separate
`event_stream` field.
- - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream.
+ - `CONDITIONAL_BLOCK`: Deprecated. Use `CONDITIONAL_ACTION` instead.
+ AUTHORIZATION event stream.
- `VELOCITY_LIMIT`: AUTHORIZATION event stream.
- `MERCHANT_LOCK`: AUTHORIZATION event stream.
- `CONDITIONAL_ACTION`: AUTHORIZATION, THREE_DS_AUTHENTICATION, TOKENIZATION,
diff --git a/src/lithic/resources/financial_accounts/__init__.py b/src/lithic/resources/financial_accounts/__init__.py
index ad35c907..74f0a994 100644
--- a/src/lithic/resources/financial_accounts/__init__.py
+++ b/src/lithic/resources/financial_accounts/__init__.py
@@ -48,6 +48,22 @@
FinancialTransactionsWithStreamingResponse,
AsyncFinancialTransactionsWithStreamingResponse,
)
+from .interest_tier_schedule import (
+ InterestTierScheduleResource,
+ AsyncInterestTierScheduleResource,
+ InterestTierScheduleResourceWithRawResponse,
+ AsyncInterestTierScheduleResourceWithRawResponse,
+ InterestTierScheduleResourceWithStreamingResponse,
+ AsyncInterestTierScheduleResourceWithStreamingResponse,
+)
+from .loan_tape_configuration import (
+ LoanTapeConfigurationResource,
+ AsyncLoanTapeConfigurationResource,
+ LoanTapeConfigurationResourceWithRawResponse,
+ AsyncLoanTapeConfigurationResourceWithRawResponse,
+ LoanTapeConfigurationResourceWithStreamingResponse,
+ AsyncLoanTapeConfigurationResourceWithStreamingResponse,
+)
__all__ = [
"Balances",
@@ -80,6 +96,18 @@
"AsyncLoanTapesWithRawResponse",
"LoanTapesWithStreamingResponse",
"AsyncLoanTapesWithStreamingResponse",
+ "LoanTapeConfigurationResource",
+ "AsyncLoanTapeConfigurationResource",
+ "LoanTapeConfigurationResourceWithRawResponse",
+ "AsyncLoanTapeConfigurationResourceWithRawResponse",
+ "LoanTapeConfigurationResourceWithStreamingResponse",
+ "AsyncLoanTapeConfigurationResourceWithStreamingResponse",
+ "InterestTierScheduleResource",
+ "AsyncInterestTierScheduleResource",
+ "InterestTierScheduleResourceWithRawResponse",
+ "AsyncInterestTierScheduleResourceWithRawResponse",
+ "InterestTierScheduleResourceWithStreamingResponse",
+ "AsyncInterestTierScheduleResourceWithStreamingResponse",
"FinancialAccounts",
"AsyncFinancialAccounts",
"FinancialAccountsWithRawResponse",
diff --git a/src/lithic/resources/financial_accounts/financial_accounts.py b/src/lithic/resources/financial_accounts/financial_accounts.py
index af68c9d5..e26c023c 100644
--- a/src/lithic/resources/financial_accounts/financial_accounts.py
+++ b/src/lithic/resources/financial_accounts/financial_accounts.py
@@ -62,6 +62,22 @@
FinancialTransactionsWithStreamingResponse,
AsyncFinancialTransactionsWithStreamingResponse,
)
+from .interest_tier_schedule import (
+ InterestTierScheduleResource,
+ AsyncInterestTierScheduleResource,
+ InterestTierScheduleResourceWithRawResponse,
+ AsyncInterestTierScheduleResourceWithRawResponse,
+ InterestTierScheduleResourceWithStreamingResponse,
+ AsyncInterestTierScheduleResourceWithStreamingResponse,
+)
+from .loan_tape_configuration import (
+ LoanTapeConfigurationResource,
+ AsyncLoanTapeConfigurationResource,
+ LoanTapeConfigurationResourceWithRawResponse,
+ AsyncLoanTapeConfigurationResourceWithRawResponse,
+ LoanTapeConfigurationResourceWithStreamingResponse,
+ AsyncLoanTapeConfigurationResourceWithStreamingResponse,
+)
from ...types.financial_account import FinancialAccount
__all__ = ["FinancialAccounts", "AsyncFinancialAccounts"]
@@ -88,6 +104,14 @@ def statements(self) -> Statements:
def loan_tapes(self) -> LoanTapes:
return LoanTapes(self._client)
+ @cached_property
+ def loan_tape_configuration(self) -> LoanTapeConfigurationResource:
+ return LoanTapeConfigurationResource(self._client)
+
+ @cached_property
+ def interest_tier_schedule(self) -> InterestTierScheduleResource:
+ return InterestTierScheduleResource(self._client)
+
@cached_property
def with_raw_response(self) -> FinancialAccountsWithRawResponse:
"""
@@ -319,7 +343,15 @@ def update_status(
financial_account_token: str,
*,
status: Literal["OPEN", "CLOSED", "SUSPENDED", "PENDING"],
- substatus: Optional[Literal["CHARGED_OFF_FRAUD", "END_USER_REQUEST", "BANK_REQUEST", "CHARGED_OFF_DELINQUENT"]],
+ substatus: Optional[
+ Literal[
+ "CHARGED_OFF_FRAUD",
+ "END_USER_REQUEST",
+ "BANK_REQUEST",
+ "CHARGED_OFF_DELINQUENT",
+ "INTEREST_AND_FEES_PAUSED",
+ ]
+ ],
user_defined_status: 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.
@@ -388,6 +420,14 @@ def statements(self) -> AsyncStatements:
def loan_tapes(self) -> AsyncLoanTapes:
return AsyncLoanTapes(self._client)
+ @cached_property
+ def loan_tape_configuration(self) -> AsyncLoanTapeConfigurationResource:
+ return AsyncLoanTapeConfigurationResource(self._client)
+
+ @cached_property
+ def interest_tier_schedule(self) -> AsyncInterestTierScheduleResource:
+ return AsyncInterestTierScheduleResource(self._client)
+
@cached_property
def with_raw_response(self) -> AsyncFinancialAccountsWithRawResponse:
"""
@@ -621,7 +661,15 @@ async def update_status(
financial_account_token: str,
*,
status: Literal["OPEN", "CLOSED", "SUSPENDED", "PENDING"],
- substatus: Optional[Literal["CHARGED_OFF_FRAUD", "END_USER_REQUEST", "BANK_REQUEST", "CHARGED_OFF_DELINQUENT"]],
+ substatus: Optional[
+ Literal[
+ "CHARGED_OFF_FRAUD",
+ "END_USER_REQUEST",
+ "BANK_REQUEST",
+ "CHARGED_OFF_DELINQUENT",
+ "INTEREST_AND_FEES_PAUSED",
+ ]
+ ],
user_defined_status: 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.
@@ -712,6 +760,14 @@ def statements(self) -> StatementsWithRawResponse:
def loan_tapes(self) -> LoanTapesWithRawResponse:
return LoanTapesWithRawResponse(self._financial_accounts.loan_tapes)
+ @cached_property
+ def loan_tape_configuration(self) -> LoanTapeConfigurationResourceWithRawResponse:
+ return LoanTapeConfigurationResourceWithRawResponse(self._financial_accounts.loan_tape_configuration)
+
+ @cached_property
+ def interest_tier_schedule(self) -> InterestTierScheduleResourceWithRawResponse:
+ return InterestTierScheduleResourceWithRawResponse(self._financial_accounts.interest_tier_schedule)
+
class AsyncFinancialAccountsWithRawResponse:
def __init__(self, financial_accounts: AsyncFinancialAccounts) -> None:
@@ -756,6 +812,14 @@ def statements(self) -> AsyncStatementsWithRawResponse:
def loan_tapes(self) -> AsyncLoanTapesWithRawResponse:
return AsyncLoanTapesWithRawResponse(self._financial_accounts.loan_tapes)
+ @cached_property
+ def loan_tape_configuration(self) -> AsyncLoanTapeConfigurationResourceWithRawResponse:
+ return AsyncLoanTapeConfigurationResourceWithRawResponse(self._financial_accounts.loan_tape_configuration)
+
+ @cached_property
+ def interest_tier_schedule(self) -> AsyncInterestTierScheduleResourceWithRawResponse:
+ return AsyncInterestTierScheduleResourceWithRawResponse(self._financial_accounts.interest_tier_schedule)
+
class FinancialAccountsWithStreamingResponse:
def __init__(self, financial_accounts: FinancialAccounts) -> None:
@@ -800,6 +864,14 @@ def statements(self) -> StatementsWithStreamingResponse:
def loan_tapes(self) -> LoanTapesWithStreamingResponse:
return LoanTapesWithStreamingResponse(self._financial_accounts.loan_tapes)
+ @cached_property
+ def loan_tape_configuration(self) -> LoanTapeConfigurationResourceWithStreamingResponse:
+ return LoanTapeConfigurationResourceWithStreamingResponse(self._financial_accounts.loan_tape_configuration)
+
+ @cached_property
+ def interest_tier_schedule(self) -> InterestTierScheduleResourceWithStreamingResponse:
+ return InterestTierScheduleResourceWithStreamingResponse(self._financial_accounts.interest_tier_schedule)
+
class AsyncFinancialAccountsWithStreamingResponse:
def __init__(self, financial_accounts: AsyncFinancialAccounts) -> None:
@@ -843,3 +915,11 @@ def statements(self) -> AsyncStatementsWithStreamingResponse:
@cached_property
def loan_tapes(self) -> AsyncLoanTapesWithStreamingResponse:
return AsyncLoanTapesWithStreamingResponse(self._financial_accounts.loan_tapes)
+
+ @cached_property
+ def loan_tape_configuration(self) -> AsyncLoanTapeConfigurationResourceWithStreamingResponse:
+ return AsyncLoanTapeConfigurationResourceWithStreamingResponse(self._financial_accounts.loan_tape_configuration)
+
+ @cached_property
+ def interest_tier_schedule(self) -> AsyncInterestTierScheduleResourceWithStreamingResponse:
+ return AsyncInterestTierScheduleResourceWithStreamingResponse(self._financial_accounts.interest_tier_schedule)
diff --git a/src/lithic/resources/financial_accounts/interest_tier_schedule.py b/src/lithic/resources/financial_accounts/interest_tier_schedule.py
new file mode 100644
index 00000000..55f13682
--- /dev/null
+++ b/src/lithic/resources/financial_accounts/interest_tier_schedule.py
@@ -0,0 +1,681 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from datetime import date
+
+import httpx
+
+from ... import _legacy_response
+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
+from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ...pagination import SyncSinglePage, AsyncSinglePage
+from ..._base_client import AsyncPaginator, make_request_options
+from ...types.financial_accounts import (
+ interest_tier_schedule_list_params,
+ interest_tier_schedule_create_params,
+ interest_tier_schedule_update_params,
+)
+from ...types.financial_accounts.interest_tier_schedule import InterestTierSchedule
+
+__all__ = ["InterestTierScheduleResource", "AsyncInterestTierScheduleResource"]
+
+
+class InterestTierScheduleResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> InterestTierScheduleResourceWithRawResponse:
+ """
+ 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/lithic-com/lithic-python#accessing-raw-response-data-eg-headers
+ """
+ return InterestTierScheduleResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> InterestTierScheduleResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/lithic-com/lithic-python#with_streaming_response
+ """
+ return InterestTierScheduleResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ financial_account_token: str,
+ *,
+ credit_product_token: str,
+ effective_date: Union[str, date],
+ tier_name: str | Omit = omit,
+ tier_rates: object | 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,
+ ) -> InterestTierSchedule:
+ """
+ Create a new interest tier schedule entry for a supported financial account
+
+ Args:
+ credit_product_token: Globally unique identifier for a credit product
+
+ effective_date: Date the tier should be effective in YYYY-MM-DD format
+
+ tier_name: Name of a tier contained in the credit product. Mutually exclusive with
+ tier_rates
+
+ tier_rates: Custom rates per category. Mutually exclusive with tier_name
+
+ 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 financial_account_token:
+ raise ValueError(
+ f"Expected a non-empty value for `financial_account_token` but received {financial_account_token!r}"
+ )
+ return self._post(
+ f"/v1/financial_accounts/{financial_account_token}/interest_tier_schedule",
+ body=maybe_transform(
+ {
+ "credit_product_token": credit_product_token,
+ "effective_date": effective_date,
+ "tier_name": tier_name,
+ "tier_rates": tier_rates,
+ },
+ interest_tier_schedule_create_params.InterestTierScheduleCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=InterestTierSchedule,
+ )
+
+ def retrieve(
+ self,
+ effective_date: Union[str, date],
+ *,
+ financial_account_token: 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,
+ ) -> InterestTierSchedule:
+ """
+ Get a specific interest tier schedule by effective date
+
+ 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 financial_account_token:
+ raise ValueError(
+ f"Expected a non-empty value for `financial_account_token` but received {financial_account_token!r}"
+ )
+ if not effective_date:
+ raise ValueError(f"Expected a non-empty value for `effective_date` but received {effective_date!r}")
+ return self._get(
+ f"/v1/financial_accounts/{financial_account_token}/interest_tier_schedule/{effective_date}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=InterestTierSchedule,
+ )
+
+ def update(
+ self,
+ effective_date: Union[str, date],
+ *,
+ financial_account_token: str,
+ tier_name: str | Omit = omit,
+ tier_rates: object | 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,
+ ) -> InterestTierSchedule:
+ """
+ Update an existing interest tier schedule
+
+ Args:
+ tier_name: Name of a tier contained in the credit product. Mutually exclusive with
+ tier_rates
+
+ tier_rates: Custom rates per category. Mutually exclusive with tier_name
+
+ 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 financial_account_token:
+ raise ValueError(
+ f"Expected a non-empty value for `financial_account_token` but received {financial_account_token!r}"
+ )
+ if not effective_date:
+ raise ValueError(f"Expected a non-empty value for `effective_date` but received {effective_date!r}")
+ return self._put(
+ f"/v1/financial_accounts/{financial_account_token}/interest_tier_schedule/{effective_date}",
+ body=maybe_transform(
+ {
+ "tier_name": tier_name,
+ "tier_rates": tier_rates,
+ },
+ interest_tier_schedule_update_params.InterestTierScheduleUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=InterestTierSchedule,
+ )
+
+ def list(
+ self,
+ financial_account_token: str,
+ *,
+ after_date: Union[str, date] | Omit = omit,
+ before_date: Union[str, date] | Omit = omit,
+ for_date: Union[str, date] | 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,
+ ) -> SyncSinglePage[InterestTierSchedule]:
+ """
+ List interest tier schedules for a financial account with optional date
+ filtering.
+
+ If no date parameters are provided, returns all tier schedules. If date
+ parameters are provided, uses filtering to return matching schedules (max 100).
+
+ - for_date: Returns exact match (takes precedence over other dates)
+ - before_date: Returns schedules with effective_date <= before_date
+ - after_date: Returns schedules with effective_date >= after_date
+ - Both before_date and after_date: Returns schedules in range
+
+ Args:
+ after_date: Return schedules with effective_date >= after_date (ISO format YYYY-MM-DD)
+
+ before_date: Return schedules with effective_date <= before_date (ISO format YYYY-MM-DD)
+
+ for_date: Return schedule with effective_date == for_date (ISO format YYYY-MM-DD)
+
+ 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 financial_account_token:
+ raise ValueError(
+ f"Expected a non-empty value for `financial_account_token` but received {financial_account_token!r}"
+ )
+ return self._get_api_list(
+ f"/v1/financial_accounts/{financial_account_token}/interest_tier_schedule",
+ page=SyncSinglePage[InterestTierSchedule],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "after_date": after_date,
+ "before_date": before_date,
+ "for_date": for_date,
+ },
+ interest_tier_schedule_list_params.InterestTierScheduleListParams,
+ ),
+ ),
+ model=InterestTierSchedule,
+ )
+
+ def delete(
+ self,
+ effective_date: Union[str, date],
+ *,
+ financial_account_token: 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,
+ ) -> None:
+ """
+ Delete an interest tier schedule entry.
+
+ Returns:
+
+ - 400 Bad Request: Invalid effective_date format OR attempting to delete the
+ earliest tier schedule entry for a non-PENDING account
+ - 404 Not Found: Tier schedule entry not found for the given effective_date OR
+ ledger account not found
+
+ Note: PENDING accounts can delete the earliest tier schedule entry (account
+ hasn't opened yet). Active/non-PENDING accounts cannot delete the earliest entry
+ to prevent orphaning the account.
+
+ If the deleted tier schedule has a past effective_date and the account is
+ ACTIVE, the loan tape rebuild configuration will be updated to trigger rebuilds
+ from that date.
+
+ 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 financial_account_token:
+ raise ValueError(
+ f"Expected a non-empty value for `financial_account_token` but received {financial_account_token!r}"
+ )
+ if not effective_date:
+ raise ValueError(f"Expected a non-empty value for `effective_date` but received {effective_date!r}")
+ return self._delete(
+ f"/v1/financial_accounts/{financial_account_token}/interest_tier_schedule/{effective_date}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class AsyncInterestTierScheduleResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncInterestTierScheduleResourceWithRawResponse:
+ """
+ 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/lithic-com/lithic-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncInterestTierScheduleResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncInterestTierScheduleResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/lithic-com/lithic-python#with_streaming_response
+ """
+ return AsyncInterestTierScheduleResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ financial_account_token: str,
+ *,
+ credit_product_token: str,
+ effective_date: Union[str, date],
+ tier_name: str | Omit = omit,
+ tier_rates: object | 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,
+ ) -> InterestTierSchedule:
+ """
+ Create a new interest tier schedule entry for a supported financial account
+
+ Args:
+ credit_product_token: Globally unique identifier for a credit product
+
+ effective_date: Date the tier should be effective in YYYY-MM-DD format
+
+ tier_name: Name of a tier contained in the credit product. Mutually exclusive with
+ tier_rates
+
+ tier_rates: Custom rates per category. Mutually exclusive with tier_name
+
+ 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 financial_account_token:
+ raise ValueError(
+ f"Expected a non-empty value for `financial_account_token` but received {financial_account_token!r}"
+ )
+ return await self._post(
+ f"/v1/financial_accounts/{financial_account_token}/interest_tier_schedule",
+ body=await async_maybe_transform(
+ {
+ "credit_product_token": credit_product_token,
+ "effective_date": effective_date,
+ "tier_name": tier_name,
+ "tier_rates": tier_rates,
+ },
+ interest_tier_schedule_create_params.InterestTierScheduleCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=InterestTierSchedule,
+ )
+
+ async def retrieve(
+ self,
+ effective_date: Union[str, date],
+ *,
+ financial_account_token: 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,
+ ) -> InterestTierSchedule:
+ """
+ Get a specific interest tier schedule by effective date
+
+ 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 financial_account_token:
+ raise ValueError(
+ f"Expected a non-empty value for `financial_account_token` but received {financial_account_token!r}"
+ )
+ if not effective_date:
+ raise ValueError(f"Expected a non-empty value for `effective_date` but received {effective_date!r}")
+ return await self._get(
+ f"/v1/financial_accounts/{financial_account_token}/interest_tier_schedule/{effective_date}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=InterestTierSchedule,
+ )
+
+ async def update(
+ self,
+ effective_date: Union[str, date],
+ *,
+ financial_account_token: str,
+ tier_name: str | Omit = omit,
+ tier_rates: object | 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,
+ ) -> InterestTierSchedule:
+ """
+ Update an existing interest tier schedule
+
+ Args:
+ tier_name: Name of a tier contained in the credit product. Mutually exclusive with
+ tier_rates
+
+ tier_rates: Custom rates per category. Mutually exclusive with tier_name
+
+ 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 financial_account_token:
+ raise ValueError(
+ f"Expected a non-empty value for `financial_account_token` but received {financial_account_token!r}"
+ )
+ if not effective_date:
+ raise ValueError(f"Expected a non-empty value for `effective_date` but received {effective_date!r}")
+ return await self._put(
+ f"/v1/financial_accounts/{financial_account_token}/interest_tier_schedule/{effective_date}",
+ body=await async_maybe_transform(
+ {
+ "tier_name": tier_name,
+ "tier_rates": tier_rates,
+ },
+ interest_tier_schedule_update_params.InterestTierScheduleUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=InterestTierSchedule,
+ )
+
+ def list(
+ self,
+ financial_account_token: str,
+ *,
+ after_date: Union[str, date] | Omit = omit,
+ before_date: Union[str, date] | Omit = omit,
+ for_date: Union[str, date] | 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[InterestTierSchedule, AsyncSinglePage[InterestTierSchedule]]:
+ """
+ List interest tier schedules for a financial account with optional date
+ filtering.
+
+ If no date parameters are provided, returns all tier schedules. If date
+ parameters are provided, uses filtering to return matching schedules (max 100).
+
+ - for_date: Returns exact match (takes precedence over other dates)
+ - before_date: Returns schedules with effective_date <= before_date
+ - after_date: Returns schedules with effective_date >= after_date
+ - Both before_date and after_date: Returns schedules in range
+
+ Args:
+ after_date: Return schedules with effective_date >= after_date (ISO format YYYY-MM-DD)
+
+ before_date: Return schedules with effective_date <= before_date (ISO format YYYY-MM-DD)
+
+ for_date: Return schedule with effective_date == for_date (ISO format YYYY-MM-DD)
+
+ 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 financial_account_token:
+ raise ValueError(
+ f"Expected a non-empty value for `financial_account_token` but received {financial_account_token!r}"
+ )
+ return self._get_api_list(
+ f"/v1/financial_accounts/{financial_account_token}/interest_tier_schedule",
+ page=AsyncSinglePage[InterestTierSchedule],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "after_date": after_date,
+ "before_date": before_date,
+ "for_date": for_date,
+ },
+ interest_tier_schedule_list_params.InterestTierScheduleListParams,
+ ),
+ ),
+ model=InterestTierSchedule,
+ )
+
+ async def delete(
+ self,
+ effective_date: Union[str, date],
+ *,
+ financial_account_token: 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,
+ ) -> None:
+ """
+ Delete an interest tier schedule entry.
+
+ Returns:
+
+ - 400 Bad Request: Invalid effective_date format OR attempting to delete the
+ earliest tier schedule entry for a non-PENDING account
+ - 404 Not Found: Tier schedule entry not found for the given effective_date OR
+ ledger account not found
+
+ Note: PENDING accounts can delete the earliest tier schedule entry (account
+ hasn't opened yet). Active/non-PENDING accounts cannot delete the earliest entry
+ to prevent orphaning the account.
+
+ If the deleted tier schedule has a past effective_date and the account is
+ ACTIVE, the loan tape rebuild configuration will be updated to trigger rebuilds
+ from that date.
+
+ 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 financial_account_token:
+ raise ValueError(
+ f"Expected a non-empty value for `financial_account_token` but received {financial_account_token!r}"
+ )
+ if not effective_date:
+ raise ValueError(f"Expected a non-empty value for `effective_date` but received {effective_date!r}")
+ return await self._delete(
+ f"/v1/financial_accounts/{financial_account_token}/interest_tier_schedule/{effective_date}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class InterestTierScheduleResourceWithRawResponse:
+ def __init__(self, interest_tier_schedule: InterestTierScheduleResource) -> None:
+ self._interest_tier_schedule = interest_tier_schedule
+
+ self.create = _legacy_response.to_raw_response_wrapper(
+ interest_tier_schedule.create,
+ )
+ self.retrieve = _legacy_response.to_raw_response_wrapper(
+ interest_tier_schedule.retrieve,
+ )
+ self.update = _legacy_response.to_raw_response_wrapper(
+ interest_tier_schedule.update,
+ )
+ self.list = _legacy_response.to_raw_response_wrapper(
+ interest_tier_schedule.list,
+ )
+ self.delete = _legacy_response.to_raw_response_wrapper(
+ interest_tier_schedule.delete,
+ )
+
+
+class AsyncInterestTierScheduleResourceWithRawResponse:
+ def __init__(self, interest_tier_schedule: AsyncInterestTierScheduleResource) -> None:
+ self._interest_tier_schedule = interest_tier_schedule
+
+ self.create = _legacy_response.async_to_raw_response_wrapper(
+ interest_tier_schedule.create,
+ )
+ self.retrieve = _legacy_response.async_to_raw_response_wrapper(
+ interest_tier_schedule.retrieve,
+ )
+ self.update = _legacy_response.async_to_raw_response_wrapper(
+ interest_tier_schedule.update,
+ )
+ self.list = _legacy_response.async_to_raw_response_wrapper(
+ interest_tier_schedule.list,
+ )
+ self.delete = _legacy_response.async_to_raw_response_wrapper(
+ interest_tier_schedule.delete,
+ )
+
+
+class InterestTierScheduleResourceWithStreamingResponse:
+ def __init__(self, interest_tier_schedule: InterestTierScheduleResource) -> None:
+ self._interest_tier_schedule = interest_tier_schedule
+
+ self.create = to_streamed_response_wrapper(
+ interest_tier_schedule.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ interest_tier_schedule.retrieve,
+ )
+ self.update = to_streamed_response_wrapper(
+ interest_tier_schedule.update,
+ )
+ self.list = to_streamed_response_wrapper(
+ interest_tier_schedule.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ interest_tier_schedule.delete,
+ )
+
+
+class AsyncInterestTierScheduleResourceWithStreamingResponse:
+ def __init__(self, interest_tier_schedule: AsyncInterestTierScheduleResource) -> None:
+ self._interest_tier_schedule = interest_tier_schedule
+
+ self.create = async_to_streamed_response_wrapper(
+ interest_tier_schedule.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ interest_tier_schedule.retrieve,
+ )
+ self.update = async_to_streamed_response_wrapper(
+ interest_tier_schedule.update,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ interest_tier_schedule.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ interest_tier_schedule.delete,
+ )
diff --git a/src/lithic/resources/financial_accounts/loan_tape_configuration.py b/src/lithic/resources/financial_accounts/loan_tape_configuration.py
new file mode 100644
index 00000000..b07b5006
--- /dev/null
+++ b/src/lithic/resources/financial_accounts/loan_tape_configuration.py
@@ -0,0 +1,167 @@
+# 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, 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.financial_accounts.loan_tape_configuration import LoanTapeConfiguration
+
+__all__ = ["LoanTapeConfigurationResource", "AsyncLoanTapeConfigurationResource"]
+
+
+class LoanTapeConfigurationResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> LoanTapeConfigurationResourceWithRawResponse:
+ """
+ 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/lithic-com/lithic-python#accessing-raw-response-data-eg-headers
+ """
+ return LoanTapeConfigurationResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> LoanTapeConfigurationResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/lithic-com/lithic-python#with_streaming_response
+ """
+ return LoanTapeConfigurationResourceWithStreamingResponse(self)
+
+ def retrieve(
+ self,
+ financial_account_token: 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,
+ ) -> LoanTapeConfiguration:
+ """
+ Get the loan tape configuration for a given financial account.
+
+ Args:
+ financial_account_token: Globally unique identifier for financial account.
+
+ 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 financial_account_token:
+ raise ValueError(
+ f"Expected a non-empty value for `financial_account_token` but received {financial_account_token!r}"
+ )
+ return self._get(
+ f"/v1/financial_accounts/{financial_account_token}/loan_tape_configuration",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=LoanTapeConfiguration,
+ )
+
+
+class AsyncLoanTapeConfigurationResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncLoanTapeConfigurationResourceWithRawResponse:
+ """
+ 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/lithic-com/lithic-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncLoanTapeConfigurationResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncLoanTapeConfigurationResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/lithic-com/lithic-python#with_streaming_response
+ """
+ return AsyncLoanTapeConfigurationResourceWithStreamingResponse(self)
+
+ async def retrieve(
+ self,
+ financial_account_token: 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,
+ ) -> LoanTapeConfiguration:
+ """
+ Get the loan tape configuration for a given financial account.
+
+ Args:
+ financial_account_token: Globally unique identifier for financial account.
+
+ 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 financial_account_token:
+ raise ValueError(
+ f"Expected a non-empty value for `financial_account_token` but received {financial_account_token!r}"
+ )
+ return await self._get(
+ f"/v1/financial_accounts/{financial_account_token}/loan_tape_configuration",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=LoanTapeConfiguration,
+ )
+
+
+class LoanTapeConfigurationResourceWithRawResponse:
+ def __init__(self, loan_tape_configuration: LoanTapeConfigurationResource) -> None:
+ self._loan_tape_configuration = loan_tape_configuration
+
+ self.retrieve = _legacy_response.to_raw_response_wrapper(
+ loan_tape_configuration.retrieve,
+ )
+
+
+class AsyncLoanTapeConfigurationResourceWithRawResponse:
+ def __init__(self, loan_tape_configuration: AsyncLoanTapeConfigurationResource) -> None:
+ self._loan_tape_configuration = loan_tape_configuration
+
+ self.retrieve = _legacy_response.async_to_raw_response_wrapper(
+ loan_tape_configuration.retrieve,
+ )
+
+
+class LoanTapeConfigurationResourceWithStreamingResponse:
+ def __init__(self, loan_tape_configuration: LoanTapeConfigurationResource) -> None:
+ self._loan_tape_configuration = loan_tape_configuration
+
+ self.retrieve = to_streamed_response_wrapper(
+ loan_tape_configuration.retrieve,
+ )
+
+
+class AsyncLoanTapeConfigurationResourceWithStreamingResponse:
+ def __init__(self, loan_tape_configuration: AsyncLoanTapeConfigurationResource) -> None:
+ self._loan_tape_configuration = loan_tape_configuration
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ loan_tape_configuration.retrieve,
+ )
diff --git a/src/lithic/types/__init__.py b/src/lithic/types/__init__.py
index 93932f6a..5532206f 100644
--- a/src/lithic/types/__init__.py
+++ b/src/lithic/types/__init__.py
@@ -33,6 +33,7 @@
from .funding_event import FundingEvent as FundingEvent
from .network_total import NetworkTotal as NetworkTotal
from .account_holder import AccountHolder as AccountHolder
+from .token_metadata import TokenMetadata as TokenMetadata
from .card_bulk_order import CardBulkOrder as CardBulkOrder
from .message_attempt import MessageAttempt as MessageAttempt
from .network_program import NetworkProgram as NetworkProgram
@@ -131,7 +132,6 @@
from .balance_updated_webhook_event import BalanceUpdatedWebhookEvent as BalanceUpdatedWebhookEvent
from .card_bulk_order_create_params import CardBulkOrderCreateParams as CardBulkOrderCreateParams
from .card_bulk_order_update_params import CardBulkOrderUpdateParams as CardBulkOrderUpdateParams
-from .digital_wallet_token_metadata import DigitalWalletTokenMetadata as DigitalWalletTokenMetadata
from .dispute_list_evidences_params import DisputeListEvidencesParams as DisputeListEvidencesParams
from .dispute_updated_webhook_event import DisputeUpdatedWebhookEvent as DisputeUpdatedWebhookEvent
from .external_bank_account_address import ExternalBankAccountAddress as ExternalBankAccountAddress
diff --git a/src/lithic/types/account_holders/__init__.py b/src/lithic/types/account_holders/__init__.py
new file mode 100644
index 00000000..f7f58159
--- /dev/null
+++ b/src/lithic/types/account_holders/__init__.py
@@ -0,0 +1,7 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .entity_create_params import EntityCreateParams as EntityCreateParams
+from .account_holder_entity import AccountHolderEntity as AccountHolderEntity
+from .entity_create_response import EntityCreateResponse as EntityCreateResponse
diff --git a/src/lithic/types/account_holders/account_holder_entity.py b/src/lithic/types/account_holders/account_holder_entity.py
new file mode 100644
index 00000000..16512cc1
--- /dev/null
+++ b/src/lithic/types/account_holders/account_holder_entity.py
@@ -0,0 +1,76 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["AccountHolderEntity", "Address"]
+
+
+class Address(BaseModel):
+ """Individual's current address"""
+
+ address1: str
+ """Valid deliverable address (no PO boxes)."""
+
+ city: str
+ """Name of city."""
+
+ country: str
+ """Valid country code.
+
+ Only USA is currently supported, entered in uppercase ISO 3166-1 alpha-3
+ three-character format.
+ """
+
+ postal_code: str
+ """Valid postal code.
+
+ Only USA ZIP codes are currently supported, entered as a five-digit ZIP or
+ nine-digit ZIP+4.
+ """
+
+ state: str
+ """Valid state code.
+
+ Only USA state codes are currently supported, entered in uppercase ISO 3166-2
+ two-character format.
+ """
+
+ address2: Optional[str] = None
+ """Unit or apartment number (if applicable)."""
+
+
+class AccountHolderEntity(BaseModel):
+ """Information about an entity associated with an account holder"""
+
+ token: str
+ """Globally unique identifier for the entity"""
+
+ account_holder_token: str
+ """Globally unique identifier for the account holder"""
+
+ address: Address
+ """Individual's current address"""
+
+ dob: Optional[str] = None
+ """Individual's date of birth, as an RFC 3339 date"""
+
+ email: Optional[str] = None
+ """Individual's email address"""
+
+ first_name: Optional[str] = None
+ """Individual's first name, as it appears on government-issued identity documents"""
+
+ last_name: Optional[str] = None
+ """Individual's last name, as it appears on government-issued identity documents"""
+
+ phone_number: Optional[str] = None
+ """Individual's phone number, entered in E.164 format"""
+
+ status: Literal["ACCEPTED", "INACTIVE", "PENDING_REVIEW", "REJECTED"]
+ """The status of the entity"""
+
+ type: Literal["BENEFICIAL_OWNER_INDIVIDUAL", "CONTROL_PERSON"]
+ """The type of entity"""
diff --git a/src/lithic/types/account_holders/entity_create_params.py b/src/lithic/types/account_holders/entity_create_params.py
new file mode 100644
index 00000000..a97fc419
--- /dev/null
+++ b/src/lithic/types/account_holders/entity_create_params.py
@@ -0,0 +1,81 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["EntityCreateParams", "Address"]
+
+
+class EntityCreateParams(TypedDict, total=False):
+ address: Required[Address]
+ """
+ Individual's current address - PO boxes, UPS drops, and FedEx drops are not
+ acceptable; APO/FPO are acceptable. Only USA addresses are currently supported.
+ """
+
+ dob: Required[str]
+ """Individual's date of birth, as an RFC 3339 date."""
+
+ email: Required[str]
+ """Individual's email address.
+
+ If utilizing Lithic for chargeback processing, this customer email address may
+ be used to communicate dispute status and resolution.
+ """
+
+ first_name: Required[str]
+ """Individual's first name, as it appears on government-issued identity documents."""
+
+ government_id: Required[str]
+ """
+ Government-issued identification number (required for identity verification and
+ compliance with banking regulations). Social Security Numbers (SSN) and
+ Individual Taxpayer Identification Numbers (ITIN) are currently supported,
+ entered as full nine-digits, with or without hyphens
+ """
+
+ last_name: Required[str]
+ """Individual's last name, as it appears on government-issued identity documents."""
+
+ phone_number: Required[str]
+ """Individual's phone number, entered in E.164 format."""
+
+ type: Required[Literal["BENEFICIAL_OWNER_INDIVIDUAL", "CONTROL_PERSON"]]
+ """The type of entity to create on the account holder"""
+
+
+class Address(TypedDict, total=False):
+ """
+ Individual's current address - PO boxes, UPS drops, and FedEx drops are not acceptable; APO/FPO are acceptable. Only USA addresses are currently supported.
+ """
+
+ address1: Required[str]
+ """Valid deliverable address (no PO boxes)."""
+
+ city: Required[str]
+ """Name of city."""
+
+ country: Required[str]
+ """Valid country code.
+
+ Only USA is currently supported, entered in uppercase ISO 3166-1 alpha-3
+ three-character format.
+ """
+
+ postal_code: Required[str]
+ """Valid postal code.
+
+ Only USA ZIP codes are currently supported, entered as a five-digit ZIP or
+ nine-digit ZIP+4.
+ """
+
+ state: Required[str]
+ """Valid state code.
+
+ Only USA state codes are currently supported, entered in uppercase ISO 3166-2
+ two-character format.
+ """
+
+ address2: str
+ """Unit or apartment number (if applicable)."""
diff --git a/src/lithic/types/account_holders/entity_create_response.py b/src/lithic/types/account_holders/entity_create_response.py
new file mode 100644
index 00000000..c316e842
--- /dev/null
+++ b/src/lithic/types/account_holders/entity_create_response.py
@@ -0,0 +1,61 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List
+from datetime import datetime
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+from ..required_document import RequiredDocument
+
+__all__ = ["EntityCreateResponse"]
+
+
+class EntityCreateResponse(BaseModel):
+ """
+ Response body for creating a new beneficial owner or replacing the control person entity on an existing KYB account holder.
+ """
+
+ token: str
+ """Globally unique identifier for the entity"""
+
+ account_holder_token: str
+ """Globally unique identifier for the account holder"""
+
+ created: datetime
+ """Timestamp of when the entity was created"""
+
+ required_documents: List[RequiredDocument]
+ """A list of documents required for the entity to be approved"""
+
+ status: Literal["ACCEPTED", "INACTIVE", "PENDING_REVIEW", "REJECTED"]
+ """Entity verification status"""
+
+ status_reasons: List[
+ Literal[
+ "ADDRESS_VERIFICATION_FAILURE",
+ "AGE_THRESHOLD_FAILURE",
+ "COMPLETE_VERIFICATION_FAILURE",
+ "DOB_VERIFICATION_FAILURE",
+ "ID_VERIFICATION_FAILURE",
+ "MAX_DOCUMENT_ATTEMPTS",
+ "MAX_RESUBMISSION_ATTEMPTS",
+ "NAME_VERIFICATION_FAILURE",
+ "OTHER_VERIFICATION_FAILURE",
+ "RISK_THRESHOLD_FAILURE",
+ "WATCHLIST_ALERT_FAILURE",
+ "PRIMARY_BUSINESS_ENTITY_ID_VERIFICATION_FAILURE",
+ "PRIMARY_BUSINESS_ENTITY_ADDRESS_VERIFICATION_FAILURE",
+ "PRIMARY_BUSINESS_ENTITY_NAME_VERIFICATION_FAILURE",
+ "PRIMARY_BUSINESS_ENTITY_BUSINESS_OFFICERS_NOT_MATCHED",
+ "PRIMARY_BUSINESS_ENTITY_SOS_FILING_INACTIVE",
+ "PRIMARY_BUSINESS_ENTITY_SOS_NOT_MATCHED",
+ "PRIMARY_BUSINESS_ENTITY_CMRA_FAILURE",
+ "PRIMARY_BUSINESS_ENTITY_WATCHLIST_FAILURE",
+ "PRIMARY_BUSINESS_ENTITY_REGISTERED_AGENT_FAILURE",
+ "CONTROL_PERSON_BLOCKLIST_ALERT_FAILURE",
+ "CONTROL_PERSON_ID_VERIFICATION_FAILURE",
+ "CONTROL_PERSON_DOB_VERIFICATION_FAILURE",
+ "CONTROL_PERSON_NAME_VERIFICATION_FAILURE",
+ ]
+ ]
+ """Reason for the evaluation status"""
diff --git a/src/lithic/types/auth_rules/auth_rule.py b/src/lithic/types/auth_rules/auth_rule.py
index 09f2f172..3708f7e1 100644
--- a/src/lithic/types/auth_rules/auth_rule.py
+++ b/src/lithic/types/auth_rules/auth_rule.py
@@ -101,7 +101,8 @@ class AuthRule(BaseModel):
evaluated. For rules that can be applied to one of several event streams, the
effective one is defined by the separate `event_stream` field.
- - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream.
+ - `CONDITIONAL_BLOCK`: Deprecated. Use `CONDITIONAL_ACTION` instead.
+ AUTHORIZATION event stream.
- `VELOCITY_LIMIT`: AUTHORIZATION event stream.
- `MERCHANT_LOCK`: AUTHORIZATION event stream.
- `CONDITIONAL_ACTION`: AUTHORIZATION, THREE_DS_AUTHENTICATION, TOKENIZATION,
diff --git a/src/lithic/types/auth_rules/conditional_block_parameters.py b/src/lithic/types/auth_rules/conditional_block_parameters.py
index b615fbe2..48f698bf 100644
--- a/src/lithic/types/auth_rules/conditional_block_parameters.py
+++ b/src/lithic/types/auth_rules/conditional_block_parameters.py
@@ -9,4 +9,6 @@
class ConditionalBlockParameters(BaseModel):
+ """Deprecated: Use CONDITIONAL_ACTION instead."""
+
conditions: List[AuthRuleCondition]
diff --git a/src/lithic/types/auth_rules/conditional_block_parameters_param.py b/src/lithic/types/auth_rules/conditional_block_parameters_param.py
index b9a456a3..539073c8 100644
--- a/src/lithic/types/auth_rules/conditional_block_parameters_param.py
+++ b/src/lithic/types/auth_rules/conditional_block_parameters_param.py
@@ -11,4 +11,6 @@
class ConditionalBlockParametersParam(TypedDict, total=False):
+ """Deprecated: Use CONDITIONAL_ACTION instead."""
+
conditions: Required[Iterable[AuthRuleConditionParam]]
diff --git a/src/lithic/types/auth_rules/v2_create_params.py b/src/lithic/types/auth_rules/v2_create_params.py
index e9f9d2d3..2af4efd9 100644
--- a/src/lithic/types/auth_rules/v2_create_params.py
+++ b/src/lithic/types/auth_rules/v2_create_params.py
@@ -37,7 +37,8 @@ class AccountLevelRule(TypedDict, total=False):
evaluated. For rules that can be applied to one of several event streams, the
effective one is defined by the separate `event_stream` field.
- - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream.
+ - `CONDITIONAL_BLOCK`: Deprecated. Use `CONDITIONAL_ACTION` instead.
+ AUTHORIZATION event stream.
- `VELOCITY_LIMIT`: AUTHORIZATION event stream.
- `MERCHANT_LOCK`: AUTHORIZATION event stream.
- `CONDITIONAL_ACTION`: AUTHORIZATION, THREE_DS_AUTHENTICATION, TOKENIZATION,
@@ -82,7 +83,8 @@ class CardLevelRule(TypedDict, total=False):
evaluated. For rules that can be applied to one of several event streams, the
effective one is defined by the separate `event_stream` field.
- - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream.
+ - `CONDITIONAL_BLOCK`: Deprecated. Use `CONDITIONAL_ACTION` instead.
+ AUTHORIZATION event stream.
- `VELOCITY_LIMIT`: AUTHORIZATION event stream.
- `MERCHANT_LOCK`: AUTHORIZATION event stream.
- `CONDITIONAL_ACTION`: AUTHORIZATION, THREE_DS_AUTHENTICATION, TOKENIZATION,
@@ -121,7 +123,8 @@ class ProgramLevelRule(TypedDict, total=False):
evaluated. For rules that can be applied to one of several event streams, the
effective one is defined by the separate `event_stream` field.
- - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream.
+ - `CONDITIONAL_BLOCK`: Deprecated. Use `CONDITIONAL_ACTION` instead.
+ AUTHORIZATION event stream.
- `VELOCITY_LIMIT`: AUTHORIZATION event stream.
- `MERCHANT_LOCK`: AUTHORIZATION event stream.
- `CONDITIONAL_ACTION`: AUTHORIZATION, THREE_DS_AUTHENTICATION, TOKENIZATION,
diff --git a/src/lithic/types/digital_wallet_tokenization_approval_request_webhook_event.py b/src/lithic/types/digital_wallet_tokenization_approval_request_webhook_event.py
index ab01de75..16e99491 100644
--- a/src/lithic/types/digital_wallet_tokenization_approval_request_webhook_event.py
+++ b/src/lithic/types/digital_wallet_tokenization_approval_request_webhook_event.py
@@ -6,11 +6,11 @@
from .device import Device
from .._models import BaseModel
+from .token_metadata import TokenMetadata
from .tokenization_tfa_reason import TokenizationTfaReason
from .wallet_decisioning_info import WalletDecisioningInfo
from .tokenization_rule_result import TokenizationRuleResult
from .tokenization_decline_reason import TokenizationDeclineReason
-from .digital_wallet_token_metadata import DigitalWalletTokenMetadata
__all__ = ["DigitalWalletTokenizationApprovalRequestWebhookEvent", "CustomerTokenizationDecision"]
@@ -46,6 +46,9 @@ class DigitalWalletTokenizationApprovalRequestWebhookEvent(BaseModel):
customer_tokenization_decision: Optional[CustomerTokenizationDecision] = None
"""Contains the metadata for the customer tokenization decision."""
+ digital_wallet_token_metadata: TokenMetadata
+ """Contains the metadata for the digital wallet being tokenized."""
+
event_type: Literal["digital_wallet.tokenization_approval_request"]
"""The name of this event"""
@@ -65,9 +68,6 @@ class DigitalWalletTokenizationApprovalRequestWebhookEvent(BaseModel):
device: Optional[Device] = None
- digital_wallet_token_metadata: Optional[DigitalWalletTokenMetadata] = None
- """Contains the metadata for the digital wallet being tokenized."""
-
rule_results: Optional[List[TokenizationRuleResult]] = None
"""Results from rules that were evaluated for this tokenization"""
diff --git a/src/lithic/types/financial_account.py b/src/lithic/types/financial_account.py
index 9c232fa6..92e7ddd4 100644
--- a/src/lithic/types/financial_account.py
+++ b/src/lithic/types/financial_account.py
@@ -47,7 +47,14 @@ class FinancialAccount(BaseModel):
"""Status of the financial account"""
substatus: Optional[
- Literal["CHARGED_OFF_DELINQUENT", "CHARGED_OFF_FRAUD", "END_USER_REQUEST", "BANK_REQUEST", "DELINQUENT"]
+ Literal[
+ "CHARGED_OFF_DELINQUENT",
+ "CHARGED_OFF_FRAUD",
+ "END_USER_REQUEST",
+ "BANK_REQUEST",
+ "DELINQUENT",
+ "INTEREST_AND_FEES_PAUSED",
+ ]
] = None
"""Substatus for the financial account"""
diff --git a/src/lithic/types/financial_account_update_status_params.py b/src/lithic/types/financial_account_update_status_params.py
index cc2d79a8..5680efee 100644
--- a/src/lithic/types/financial_account_update_status_params.py
+++ b/src/lithic/types/financial_account_update_status_params.py
@@ -13,7 +13,15 @@ class FinancialAccountUpdateStatusParams(TypedDict, total=False):
"""Status of the financial account"""
substatus: Required[
- Optional[Literal["CHARGED_OFF_FRAUD", "END_USER_REQUEST", "BANK_REQUEST", "CHARGED_OFF_DELINQUENT"]]
+ Optional[
+ Literal[
+ "CHARGED_OFF_FRAUD",
+ "END_USER_REQUEST",
+ "BANK_REQUEST",
+ "CHARGED_OFF_DELINQUENT",
+ "INTEREST_AND_FEES_PAUSED",
+ ]
+ ]
]
"""Substatus for the financial account"""
diff --git a/src/lithic/types/financial_accounts/__init__.py b/src/lithic/types/financial_accounts/__init__.py
index 0a094585..1938293c 100644
--- a/src/lithic/types/financial_accounts/__init__.py
+++ b/src/lithic/types/financial_accounts/__init__.py
@@ -9,6 +9,12 @@
from .balance_list_params import BalanceListParams as BalanceListParams
from .loan_tape_list_params import LoanTapeListParams as LoanTapeListParams
from .statement_list_params import StatementListParams as StatementListParams
+from .interest_tier_schedule import InterestTierSchedule as InterestTierSchedule
+from .loan_tape_configuration import LoanTapeConfiguration as LoanTapeConfiguration
from .financial_account_credit_config import FinancialAccountCreditConfig as FinancialAccountCreditConfig
+from .loan_tape_rebuild_configuration import LoanTapeRebuildConfiguration as LoanTapeRebuildConfiguration
from .financial_transaction_list_params import FinancialTransactionListParams as FinancialTransactionListParams
from .credit_configuration_update_params import CreditConfigurationUpdateParams as CreditConfigurationUpdateParams
+from .interest_tier_schedule_list_params import InterestTierScheduleListParams as InterestTierScheduleListParams
+from .interest_tier_schedule_create_params import InterestTierScheduleCreateParams as InterestTierScheduleCreateParams
+from .interest_tier_schedule_update_params import InterestTierScheduleUpdateParams as InterestTierScheduleUpdateParams
diff --git a/src/lithic/types/financial_accounts/interest_tier_schedule.py b/src/lithic/types/financial_accounts/interest_tier_schedule.py
new file mode 100644
index 00000000..de815562
--- /dev/null
+++ b/src/lithic/types/financial_accounts/interest_tier_schedule.py
@@ -0,0 +1,27 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import date
+
+from ..._models import BaseModel
+
+__all__ = ["InterestTierSchedule"]
+
+
+class InterestTierSchedule(BaseModel):
+ """Entry in the Tier Schedule of an account"""
+
+ credit_product_token: str
+ """Globally unique identifier for a credit product"""
+
+ effective_date: date
+ """Date the tier should be effective in YYYY-MM-DD format"""
+
+ tier_name: Optional[str] = None
+ """Name of a tier contained in the credit product.
+
+ Mutually exclusive with tier_rates
+ """
+
+ tier_rates: Optional[object] = None
+ """Custom rates per category. Mutually exclusive with tier_name"""
diff --git a/src/lithic/types/financial_accounts/interest_tier_schedule_create_params.py b/src/lithic/types/financial_accounts/interest_tier_schedule_create_params.py
new file mode 100644
index 00000000..dc7c11e9
--- /dev/null
+++ b/src/lithic/types/financial_accounts/interest_tier_schedule_create_params.py
@@ -0,0 +1,28 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from datetime import date
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["InterestTierScheduleCreateParams"]
+
+
+class InterestTierScheduleCreateParams(TypedDict, total=False):
+ credit_product_token: Required[str]
+ """Globally unique identifier for a credit product"""
+
+ effective_date: Required[Annotated[Union[str, date], PropertyInfo(format="iso8601")]]
+ """Date the tier should be effective in YYYY-MM-DD format"""
+
+ tier_name: str
+ """Name of a tier contained in the credit product.
+
+ Mutually exclusive with tier_rates
+ """
+
+ tier_rates: object
+ """Custom rates per category. Mutually exclusive with tier_name"""
diff --git a/src/lithic/types/financial_accounts/interest_tier_schedule_list_params.py b/src/lithic/types/financial_accounts/interest_tier_schedule_list_params.py
new file mode 100644
index 00000000..094f9ac1
--- /dev/null
+++ b/src/lithic/types/financial_accounts/interest_tier_schedule_list_params.py
@@ -0,0 +1,22 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from datetime import date
+from typing_extensions import Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["InterestTierScheduleListParams"]
+
+
+class InterestTierScheduleListParams(TypedDict, total=False):
+ after_date: Annotated[Union[str, date], PropertyInfo(format="iso8601")]
+ """Return schedules with effective_date >= after_date (ISO format YYYY-MM-DD)"""
+
+ before_date: Annotated[Union[str, date], PropertyInfo(format="iso8601")]
+ """Return schedules with effective_date <= before_date (ISO format YYYY-MM-DD)"""
+
+ for_date: Annotated[Union[str, date], PropertyInfo(format="iso8601")]
+ """Return schedule with effective_date == for_date (ISO format YYYY-MM-DD)"""
diff --git a/src/lithic/types/financial_accounts/interest_tier_schedule_update_params.py b/src/lithic/types/financial_accounts/interest_tier_schedule_update_params.py
new file mode 100644
index 00000000..dd1cd9c0
--- /dev/null
+++ b/src/lithic/types/financial_accounts/interest_tier_schedule_update_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_extensions import Required, TypedDict
+
+__all__ = ["InterestTierScheduleUpdateParams"]
+
+
+class InterestTierScheduleUpdateParams(TypedDict, total=False):
+ financial_account_token: Required[str]
+
+ tier_name: str
+ """Name of a tier contained in the credit product.
+
+ Mutually exclusive with tier_rates
+ """
+
+ tier_rates: object
+ """Custom rates per category. Mutually exclusive with tier_name"""
diff --git a/src/lithic/types/financial_accounts/loan_tape.py b/src/lithic/types/financial_accounts/loan_tape.py
index 6c16a8ca..583f98cd 100644
--- a/src/lithic/types/financial_accounts/loan_tape.py
+++ b/src/lithic/types/financial_accounts/loan_tape.py
@@ -28,7 +28,14 @@ class AccountStandingFinancialAccountState(BaseModel):
"""Status of the financial account"""
substatus: Optional[
- Literal["CHARGED_OFF_DELINQUENT", "CHARGED_OFF_FRAUD", "END_USER_REQUEST", "BANK_REQUEST", "DELINQUENT"]
+ Literal[
+ "CHARGED_OFF_DELINQUENT",
+ "CHARGED_OFF_FRAUD",
+ "END_USER_REQUEST",
+ "BANK_REQUEST",
+ "DELINQUENT",
+ "INTEREST_AND_FEES_PAUSED",
+ ]
] = None
"""Substatus for the financial account"""
diff --git a/src/lithic/types/financial_accounts/loan_tape_configuration.py b/src/lithic/types/financial_accounts/loan_tape_configuration.py
new file mode 100644
index 00000000..02554353
--- /dev/null
+++ b/src/lithic/types/financial_accounts/loan_tape_configuration.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 ..._models import BaseModel
+from .loan_tape_rebuild_configuration import LoanTapeRebuildConfiguration
+
+__all__ = ["LoanTapeConfiguration"]
+
+
+class LoanTapeConfiguration(BaseModel):
+ """Configuration for loan tapes"""
+
+ created_at: datetime
+
+ financial_account_token: str
+
+ instance_token: str
+
+ updated_at: datetime
+
+ credit_product_token: Optional[str] = None
+
+ loan_tape_rebuild_configuration: Optional[LoanTapeRebuildConfiguration] = None
+ """Configuration for building loan tapes"""
+
+ tier_schedule_changed_at: Optional[datetime] = None
diff --git a/src/lithic/types/financial_accounts/loan_tape_rebuild_configuration.py b/src/lithic/types/financial_accounts/loan_tape_rebuild_configuration.py
new file mode 100644
index 00000000..81fadc2c
--- /dev/null
+++ b/src/lithic/types/financial_accounts/loan_tape_rebuild_configuration.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import date
+
+from ..._models import BaseModel
+
+__all__ = ["LoanTapeRebuildConfiguration"]
+
+
+class LoanTapeRebuildConfiguration(BaseModel):
+ """Configuration for building loan tapes"""
+
+ rebuild_needed: bool
+ """Whether the account's loan tapes need to be rebuilt or not"""
+
+ last_rebuild: Optional[date] = None
+ """The date for which the account's loan tapes were last rebuilt"""
+
+ rebuild_from: Optional[date] = None
+ """Date from which to start rebuilding from if the account requires a rebuild"""
diff --git a/src/lithic/types/financial_accounts/statement.py b/src/lithic/types/financial_accounts/statement.py
index 37b8884d..513630fb 100644
--- a/src/lithic/types/financial_accounts/statement.py
+++ b/src/lithic/types/financial_accounts/statement.py
@@ -25,7 +25,14 @@ class AccountStandingFinancialAccountState(BaseModel):
"""Status of the financial account"""
substatus: Optional[
- Literal["CHARGED_OFF_DELINQUENT", "CHARGED_OFF_FRAUD", "END_USER_REQUEST", "BANK_REQUEST", "DELINQUENT"]
+ Literal[
+ "CHARGED_OFF_DELINQUENT",
+ "CHARGED_OFF_FRAUD",
+ "END_USER_REQUEST",
+ "BANK_REQUEST",
+ "DELINQUENT",
+ "INTEREST_AND_FEES_PAUSED",
+ ]
] = None
"""Substatus for the financial account"""
diff --git a/src/lithic/types/digital_wallet_token_metadata.py b/src/lithic/types/token_metadata.py
similarity index 93%
rename from src/lithic/types/digital_wallet_token_metadata.py
rename to src/lithic/types/token_metadata.py
index 2e26e00c..f8df2d11 100644
--- a/src/lithic/types/digital_wallet_token_metadata.py
+++ b/src/lithic/types/token_metadata.py
@@ -5,7 +5,7 @@
from .._models import BaseModel
-__all__ = ["DigitalWalletTokenMetadata", "PaymentAccountInfo", "PaymentAccountInfoAccountHolderData"]
+__all__ = ["TokenMetadata", "PaymentAccountInfo", "PaymentAccountInfoAccountHolderData"]
class PaymentAccountInfoAccountHolderData(BaseModel):
@@ -42,7 +42,7 @@ class PaymentAccountInfo(BaseModel):
"""
-class DigitalWalletTokenMetadata(BaseModel):
+class TokenMetadata(BaseModel):
"""Contains the metadata for the digital wallet being tokenized."""
payment_account_info: PaymentAccountInfo
@@ -68,6 +68,7 @@ class DigitalWalletTokenMetadata(BaseModel):
"FACEBOOK",
"FITBIT_PAY",
"GARMIN_PAY",
+ "GOOGLE_PAY",
"MICROSOFT_PAY",
"NETFLIX",
"SAMSUNG_PAY",
diff --git a/src/lithic/types/tokenization_approval_request_webhook_event.py b/src/lithic/types/tokenization_approval_request_webhook_event.py
index 9e6e6f11..f5e0df25 100644
--- a/src/lithic/types/tokenization_approval_request_webhook_event.py
+++ b/src/lithic/types/tokenization_approval_request_webhook_event.py
@@ -6,11 +6,11 @@
from .device import Device
from .._models import BaseModel
+from .token_metadata import TokenMetadata
from .tokenization_tfa_reason import TokenizationTfaReason
from .wallet_decisioning_info import WalletDecisioningInfo
from .tokenization_rule_result import TokenizationRuleResult
from .tokenization_decline_reason import TokenizationDeclineReason
-from .digital_wallet_token_metadata import DigitalWalletTokenMetadata
__all__ = ["TokenizationApprovalRequestWebhookEvent", "CustomerTokenizationDecision"]
@@ -55,6 +55,9 @@ class TokenizationApprovalRequestWebhookEvent(BaseModel):
APPROVED/VERIFICATION_REQUIRED/DENIED.
"""
+ token_metadata: TokenMetadata
+ """Contains the metadata for the digital wallet being tokenized."""
+
tokenization_channel: Literal["DIGITAL_WALLET", "MERCHANT"]
"""The channel through which the tokenization was made."""
@@ -65,9 +68,6 @@ class TokenizationApprovalRequestWebhookEvent(BaseModel):
device: Optional[Device] = None
- digital_wallet_token_metadata: Optional[DigitalWalletTokenMetadata] = None
- """Contains the metadata for the digital wallet being tokenized."""
-
rule_results: Optional[List[TokenizationRuleResult]] = None
"""Results from rules that were evaluated for this tokenization"""
diff --git a/src/lithic/types/tokenization_decisioning_request_webhook_event.py b/src/lithic/types/tokenization_decisioning_request_webhook_event.py
index 957d6266..c44df2dc 100644
--- a/src/lithic/types/tokenization_decisioning_request_webhook_event.py
+++ b/src/lithic/types/tokenization_decisioning_request_webhook_event.py
@@ -6,8 +6,8 @@
from .device import Device
from .._models import BaseModel
+from .token_metadata import TokenMetadata
from .wallet_decisioning_info import WalletDecisioningInfo
-from .digital_wallet_token_metadata import DigitalWalletTokenMetadata
__all__ = ["TokenizationDecisioningRequestWebhookEvent"]
@@ -26,6 +26,9 @@ class TokenizationDecisioningRequestWebhookEvent(BaseModel):
created: datetime
"""Indicate when the request was received from Mastercard or Visa"""
+ digital_wallet_token_metadata: TokenMetadata
+ """Contains the metadata for the digital wallet being tokenized."""
+
event_type: Literal["digital_wallet.tokenization_approval_request"]
"""The name of this event"""
@@ -45,9 +48,6 @@ class TokenizationDecisioningRequestWebhookEvent(BaseModel):
device: Optional[Device] = None
- digital_wallet_token_metadata: Optional[DigitalWalletTokenMetadata] = None
- """Contains the metadata for the digital wallet being tokenized."""
-
tokenization_source: Optional[
Literal["ACCOUNT_ON_FILE", "CONTACTLESS_TAP", "MANUAL_PROVISION", "PUSH_PROVISION", "TOKEN", "UNKNOWN"]
] = None
diff --git a/tests/api_resources/account_holders/__init__.py b/tests/api_resources/account_holders/__init__.py
new file mode 100644
index 00000000..fd8019a9
--- /dev/null
+++ b/tests/api_resources/account_holders/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/account_holders/test_entities.py b/tests/api_resources/account_holders/test_entities.py
new file mode 100644
index 00000000..7013ad53
--- /dev/null
+++ b/tests/api_resources/account_holders/test_entities.py
@@ -0,0 +1,352 @@
+# 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 lithic import Lithic, AsyncLithic
+from tests.utils import assert_matches_type
+from lithic.types.account_holders import AccountHolderEntity, EntityCreateResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestEntities:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: Lithic) -> None:
+ entity = client.account_holders.entities.create(
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ address={
+ "address1": "300 Normal Forest Way",
+ "city": "Portland",
+ "country": "USA",
+ "postal_code": "90210",
+ "state": "OR",
+ },
+ dob="1991-03-08T08:00:00Z",
+ email="tim@left-earth.com",
+ first_name="Timmy",
+ government_id="211-23-1412",
+ last_name="Turner",
+ phone_number="+15555555555",
+ type="BENEFICIAL_OWNER_INDIVIDUAL",
+ )
+ assert_matches_type(EntityCreateResponse, entity, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: Lithic) -> None:
+ entity = client.account_holders.entities.create(
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ address={
+ "address1": "300 Normal Forest Way",
+ "city": "Portland",
+ "country": "USA",
+ "postal_code": "90210",
+ "state": "OR",
+ "address2": "address2",
+ },
+ dob="1991-03-08T08:00:00Z",
+ email="tim@left-earth.com",
+ first_name="Timmy",
+ government_id="211-23-1412",
+ last_name="Turner",
+ phone_number="+15555555555",
+ type="BENEFICIAL_OWNER_INDIVIDUAL",
+ )
+ assert_matches_type(EntityCreateResponse, entity, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: Lithic) -> None:
+ response = client.account_holders.entities.with_raw_response.create(
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ address={
+ "address1": "300 Normal Forest Way",
+ "city": "Portland",
+ "country": "USA",
+ "postal_code": "90210",
+ "state": "OR",
+ },
+ dob="1991-03-08T08:00:00Z",
+ email="tim@left-earth.com",
+ first_name="Timmy",
+ government_id="211-23-1412",
+ last_name="Turner",
+ phone_number="+15555555555",
+ type="BENEFICIAL_OWNER_INDIVIDUAL",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ entity = response.parse()
+ assert_matches_type(EntityCreateResponse, entity, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: Lithic) -> None:
+ with client.account_holders.entities.with_streaming_response.create(
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ address={
+ "address1": "300 Normal Forest Way",
+ "city": "Portland",
+ "country": "USA",
+ "postal_code": "90210",
+ "state": "OR",
+ },
+ dob="1991-03-08T08:00:00Z",
+ email="tim@left-earth.com",
+ first_name="Timmy",
+ government_id="211-23-1412",
+ last_name="Turner",
+ phone_number="+15555555555",
+ type="BENEFICIAL_OWNER_INDIVIDUAL",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ entity = response.parse()
+ assert_matches_type(EntityCreateResponse, entity, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_create(self, client: Lithic) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_holder_token` but received ''"):
+ client.account_holders.entities.with_raw_response.create(
+ account_holder_token="",
+ address={
+ "address1": "300 Normal Forest Way",
+ "city": "Portland",
+ "country": "USA",
+ "postal_code": "90210",
+ "state": "OR",
+ },
+ dob="1991-03-08T08:00:00Z",
+ email="tim@left-earth.com",
+ first_name="Timmy",
+ government_id="211-23-1412",
+ last_name="Turner",
+ phone_number="+15555555555",
+ type="BENEFICIAL_OWNER_INDIVIDUAL",
+ )
+
+ @parametrize
+ def test_method_delete(self, client: Lithic) -> None:
+ entity = client.account_holders.entities.delete(
+ entity_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(AccountHolderEntity, entity, path=["response"])
+
+ @parametrize
+ def test_raw_response_delete(self, client: Lithic) -> None:
+ response = client.account_holders.entities.with_raw_response.delete(
+ entity_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ entity = response.parse()
+ assert_matches_type(AccountHolderEntity, entity, path=["response"])
+
+ @parametrize
+ def test_streaming_response_delete(self, client: Lithic) -> None:
+ with client.account_holders.entities.with_streaming_response.delete(
+ entity_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ entity = response.parse()
+ assert_matches_type(AccountHolderEntity, entity, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_delete(self, client: Lithic) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_holder_token` but received ''"):
+ client.account_holders.entities.with_raw_response.delete(
+ entity_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ account_holder_token="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `entity_token` but received ''"):
+ client.account_holders.entities.with_raw_response.delete(
+ entity_token="",
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+
+class TestAsyncEntities:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_create(self, async_client: AsyncLithic) -> None:
+ entity = await async_client.account_holders.entities.create(
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ address={
+ "address1": "300 Normal Forest Way",
+ "city": "Portland",
+ "country": "USA",
+ "postal_code": "90210",
+ "state": "OR",
+ },
+ dob="1991-03-08T08:00:00Z",
+ email="tim@left-earth.com",
+ first_name="Timmy",
+ government_id="211-23-1412",
+ last_name="Turner",
+ phone_number="+15555555555",
+ type="BENEFICIAL_OWNER_INDIVIDUAL",
+ )
+ assert_matches_type(EntityCreateResponse, entity, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncLithic) -> None:
+ entity = await async_client.account_holders.entities.create(
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ address={
+ "address1": "300 Normal Forest Way",
+ "city": "Portland",
+ "country": "USA",
+ "postal_code": "90210",
+ "state": "OR",
+ "address2": "address2",
+ },
+ dob="1991-03-08T08:00:00Z",
+ email="tim@left-earth.com",
+ first_name="Timmy",
+ government_id="211-23-1412",
+ last_name="Turner",
+ phone_number="+15555555555",
+ type="BENEFICIAL_OWNER_INDIVIDUAL",
+ )
+ assert_matches_type(EntityCreateResponse, entity, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncLithic) -> None:
+ response = await async_client.account_holders.entities.with_raw_response.create(
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ address={
+ "address1": "300 Normal Forest Way",
+ "city": "Portland",
+ "country": "USA",
+ "postal_code": "90210",
+ "state": "OR",
+ },
+ dob="1991-03-08T08:00:00Z",
+ email="tim@left-earth.com",
+ first_name="Timmy",
+ government_id="211-23-1412",
+ last_name="Turner",
+ phone_number="+15555555555",
+ type="BENEFICIAL_OWNER_INDIVIDUAL",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ entity = response.parse()
+ assert_matches_type(EntityCreateResponse, entity, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncLithic) -> None:
+ async with async_client.account_holders.entities.with_streaming_response.create(
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ address={
+ "address1": "300 Normal Forest Way",
+ "city": "Portland",
+ "country": "USA",
+ "postal_code": "90210",
+ "state": "OR",
+ },
+ dob="1991-03-08T08:00:00Z",
+ email="tim@left-earth.com",
+ first_name="Timmy",
+ government_id="211-23-1412",
+ last_name="Turner",
+ phone_number="+15555555555",
+ type="BENEFICIAL_OWNER_INDIVIDUAL",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ entity = await response.parse()
+ assert_matches_type(EntityCreateResponse, entity, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_create(self, async_client: AsyncLithic) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_holder_token` but received ''"):
+ await async_client.account_holders.entities.with_raw_response.create(
+ account_holder_token="",
+ address={
+ "address1": "300 Normal Forest Way",
+ "city": "Portland",
+ "country": "USA",
+ "postal_code": "90210",
+ "state": "OR",
+ },
+ dob="1991-03-08T08:00:00Z",
+ email="tim@left-earth.com",
+ first_name="Timmy",
+ government_id="211-23-1412",
+ last_name="Turner",
+ phone_number="+15555555555",
+ type="BENEFICIAL_OWNER_INDIVIDUAL",
+ )
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncLithic) -> None:
+ entity = await async_client.account_holders.entities.delete(
+ entity_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(AccountHolderEntity, entity, path=["response"])
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncLithic) -> None:
+ response = await async_client.account_holders.entities.with_raw_response.delete(
+ entity_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ entity = response.parse()
+ assert_matches_type(AccountHolderEntity, entity, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncLithic) -> None:
+ async with async_client.account_holders.entities.with_streaming_response.delete(
+ entity_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ entity = await response.parse()
+ assert_matches_type(AccountHolderEntity, entity, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_delete(self, async_client: AsyncLithic) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_holder_token` but received ''"):
+ await async_client.account_holders.entities.with_raw_response.delete(
+ entity_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ account_holder_token="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `entity_token` but received ''"):
+ await async_client.account_holders.entities.with_raw_response.delete(
+ entity_token="",
+ account_holder_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
diff --git a/tests/api_resources/financial_accounts/test_interest_tier_schedule.py b/tests/api_resources/financial_accounts/test_interest_tier_schedule.py
new file mode 100644
index 00000000..fcac228d
--- /dev/null
+++ b/tests/api_resources/financial_accounts/test_interest_tier_schedule.py
@@ -0,0 +1,566 @@
+# 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 lithic import Lithic, AsyncLithic
+from tests.utils import assert_matches_type
+from lithic._utils import parse_date
+from lithic.pagination import SyncSinglePage, AsyncSinglePage
+from lithic.types.financial_accounts import (
+ InterestTierSchedule,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestInterestTierSchedule:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: Lithic) -> None:
+ interest_tier_schedule = client.financial_accounts.interest_tier_schedule.create(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ credit_product_token="credit_product_token",
+ effective_date=parse_date("2019-12-27"),
+ )
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: Lithic) -> None:
+ interest_tier_schedule = client.financial_accounts.interest_tier_schedule.create(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ credit_product_token="credit_product_token",
+ effective_date=parse_date("2019-12-27"),
+ tier_name="tier_name",
+ tier_rates={},
+ )
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: Lithic) -> None:
+ response = client.financial_accounts.interest_tier_schedule.with_raw_response.create(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ credit_product_token="credit_product_token",
+ effective_date=parse_date("2019-12-27"),
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ interest_tier_schedule = response.parse()
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: Lithic) -> None:
+ with client.financial_accounts.interest_tier_schedule.with_streaming_response.create(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ credit_product_token="credit_product_token",
+ effective_date=parse_date("2019-12-27"),
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ interest_tier_schedule = response.parse()
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_create(self, client: Lithic) -> None:
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `financial_account_token` but received ''"
+ ):
+ client.financial_accounts.interest_tier_schedule.with_raw_response.create(
+ financial_account_token="",
+ credit_product_token="credit_product_token",
+ effective_date=parse_date("2019-12-27"),
+ )
+
+ @parametrize
+ def test_method_retrieve(self, client: Lithic) -> None:
+ interest_tier_schedule = client.financial_accounts.interest_tier_schedule.retrieve(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Lithic) -> None:
+ response = client.financial_accounts.interest_tier_schedule.with_raw_response.retrieve(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ interest_tier_schedule = response.parse()
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Lithic) -> None:
+ with client.financial_accounts.interest_tier_schedule.with_streaming_response.retrieve(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ interest_tier_schedule = response.parse()
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: Lithic) -> None:
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `financial_account_token` but received ''"
+ ):
+ client.financial_accounts.interest_tier_schedule.with_raw_response.retrieve(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `effective_date` but received ''"):
+ client.financial_accounts.interest_tier_schedule.with_raw_response.retrieve(
+ effective_date="",
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ @parametrize
+ def test_method_update(self, client: Lithic) -> None:
+ interest_tier_schedule = client.financial_accounts.interest_tier_schedule.update(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ def test_method_update_with_all_params(self, client: Lithic) -> None:
+ interest_tier_schedule = client.financial_accounts.interest_tier_schedule.update(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ tier_name="tier_name",
+ tier_rates={},
+ )
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ def test_raw_response_update(self, client: Lithic) -> None:
+ response = client.financial_accounts.interest_tier_schedule.with_raw_response.update(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ interest_tier_schedule = response.parse()
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ def test_streaming_response_update(self, client: Lithic) -> None:
+ with client.financial_accounts.interest_tier_schedule.with_streaming_response.update(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ interest_tier_schedule = response.parse()
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_update(self, client: Lithic) -> None:
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `financial_account_token` but received ''"
+ ):
+ client.financial_accounts.interest_tier_schedule.with_raw_response.update(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `effective_date` but received ''"):
+ client.financial_accounts.interest_tier_schedule.with_raw_response.update(
+ effective_date="",
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ @parametrize
+ def test_method_list(self, client: Lithic) -> None:
+ interest_tier_schedule = client.financial_accounts.interest_tier_schedule.list(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(SyncSinglePage[InterestTierSchedule], interest_tier_schedule, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Lithic) -> None:
+ interest_tier_schedule = client.financial_accounts.interest_tier_schedule.list(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ after_date=parse_date("2019-12-27"),
+ before_date=parse_date("2019-12-27"),
+ for_date=parse_date("2019-12-27"),
+ )
+ assert_matches_type(SyncSinglePage[InterestTierSchedule], interest_tier_schedule, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Lithic) -> None:
+ response = client.financial_accounts.interest_tier_schedule.with_raw_response.list(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ interest_tier_schedule = response.parse()
+ assert_matches_type(SyncSinglePage[InterestTierSchedule], interest_tier_schedule, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Lithic) -> None:
+ with client.financial_accounts.interest_tier_schedule.with_streaming_response.list(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ interest_tier_schedule = response.parse()
+ assert_matches_type(SyncSinglePage[InterestTierSchedule], interest_tier_schedule, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_list(self, client: Lithic) -> None:
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `financial_account_token` but received ''"
+ ):
+ client.financial_accounts.interest_tier_schedule.with_raw_response.list(
+ financial_account_token="",
+ )
+
+ @parametrize
+ def test_method_delete(self, client: Lithic) -> None:
+ interest_tier_schedule = client.financial_accounts.interest_tier_schedule.delete(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert interest_tier_schedule is None
+
+ @parametrize
+ def test_raw_response_delete(self, client: Lithic) -> None:
+ response = client.financial_accounts.interest_tier_schedule.with_raw_response.delete(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ interest_tier_schedule = response.parse()
+ assert interest_tier_schedule is None
+
+ @parametrize
+ def test_streaming_response_delete(self, client: Lithic) -> None:
+ with client.financial_accounts.interest_tier_schedule.with_streaming_response.delete(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ interest_tier_schedule = response.parse()
+ assert interest_tier_schedule is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_delete(self, client: Lithic) -> None:
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `financial_account_token` but received ''"
+ ):
+ client.financial_accounts.interest_tier_schedule.with_raw_response.delete(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `effective_date` but received ''"):
+ client.financial_accounts.interest_tier_schedule.with_raw_response.delete(
+ effective_date="",
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+
+class TestAsyncInterestTierSchedule:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_create(self, async_client: AsyncLithic) -> None:
+ interest_tier_schedule = await async_client.financial_accounts.interest_tier_schedule.create(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ credit_product_token="credit_product_token",
+ effective_date=parse_date("2019-12-27"),
+ )
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncLithic) -> None:
+ interest_tier_schedule = await async_client.financial_accounts.interest_tier_schedule.create(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ credit_product_token="credit_product_token",
+ effective_date=parse_date("2019-12-27"),
+ tier_name="tier_name",
+ tier_rates={},
+ )
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncLithic) -> None:
+ response = await async_client.financial_accounts.interest_tier_schedule.with_raw_response.create(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ credit_product_token="credit_product_token",
+ effective_date=parse_date("2019-12-27"),
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ interest_tier_schedule = response.parse()
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncLithic) -> None:
+ async with async_client.financial_accounts.interest_tier_schedule.with_streaming_response.create(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ credit_product_token="credit_product_token",
+ effective_date=parse_date("2019-12-27"),
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ interest_tier_schedule = await response.parse()
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_create(self, async_client: AsyncLithic) -> None:
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `financial_account_token` but received ''"
+ ):
+ await async_client.financial_accounts.interest_tier_schedule.with_raw_response.create(
+ financial_account_token="",
+ credit_product_token="credit_product_token",
+ effective_date=parse_date("2019-12-27"),
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncLithic) -> None:
+ interest_tier_schedule = await async_client.financial_accounts.interest_tier_schedule.retrieve(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncLithic) -> None:
+ response = await async_client.financial_accounts.interest_tier_schedule.with_raw_response.retrieve(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ interest_tier_schedule = response.parse()
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncLithic) -> None:
+ async with async_client.financial_accounts.interest_tier_schedule.with_streaming_response.retrieve(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ interest_tier_schedule = await response.parse()
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncLithic) -> None:
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `financial_account_token` but received ''"
+ ):
+ await async_client.financial_accounts.interest_tier_schedule.with_raw_response.retrieve(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `effective_date` but received ''"):
+ await async_client.financial_accounts.interest_tier_schedule.with_raw_response.retrieve(
+ effective_date="",
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ @parametrize
+ async def test_method_update(self, async_client: AsyncLithic) -> None:
+ interest_tier_schedule = await async_client.financial_accounts.interest_tier_schedule.update(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ async def test_method_update_with_all_params(self, async_client: AsyncLithic) -> None:
+ interest_tier_schedule = await async_client.financial_accounts.interest_tier_schedule.update(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ tier_name="tier_name",
+ tier_rates={},
+ )
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ async def test_raw_response_update(self, async_client: AsyncLithic) -> None:
+ response = await async_client.financial_accounts.interest_tier_schedule.with_raw_response.update(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ interest_tier_schedule = response.parse()
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_update(self, async_client: AsyncLithic) -> None:
+ async with async_client.financial_accounts.interest_tier_schedule.with_streaming_response.update(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ interest_tier_schedule = await response.parse()
+ assert_matches_type(InterestTierSchedule, interest_tier_schedule, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_update(self, async_client: AsyncLithic) -> None:
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `financial_account_token` but received ''"
+ ):
+ await async_client.financial_accounts.interest_tier_schedule.with_raw_response.update(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `effective_date` but received ''"):
+ await async_client.financial_accounts.interest_tier_schedule.with_raw_response.update(
+ effective_date="",
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncLithic) -> None:
+ interest_tier_schedule = await async_client.financial_accounts.interest_tier_schedule.list(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(AsyncSinglePage[InterestTierSchedule], interest_tier_schedule, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncLithic) -> None:
+ interest_tier_schedule = await async_client.financial_accounts.interest_tier_schedule.list(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ after_date=parse_date("2019-12-27"),
+ before_date=parse_date("2019-12-27"),
+ for_date=parse_date("2019-12-27"),
+ )
+ assert_matches_type(AsyncSinglePage[InterestTierSchedule], interest_tier_schedule, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncLithic) -> None:
+ response = await async_client.financial_accounts.interest_tier_schedule.with_raw_response.list(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ interest_tier_schedule = response.parse()
+ assert_matches_type(AsyncSinglePage[InterestTierSchedule], interest_tier_schedule, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncLithic) -> None:
+ async with async_client.financial_accounts.interest_tier_schedule.with_streaming_response.list(
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ interest_tier_schedule = await response.parse()
+ assert_matches_type(AsyncSinglePage[InterestTierSchedule], interest_tier_schedule, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_list(self, async_client: AsyncLithic) -> None:
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `financial_account_token` but received ''"
+ ):
+ await async_client.financial_accounts.interest_tier_schedule.with_raw_response.list(
+ financial_account_token="",
+ )
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncLithic) -> None:
+ interest_tier_schedule = await async_client.financial_accounts.interest_tier_schedule.delete(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert interest_tier_schedule is None
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncLithic) -> None:
+ response = await async_client.financial_accounts.interest_tier_schedule.with_raw_response.delete(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ interest_tier_schedule = response.parse()
+ assert interest_tier_schedule is None
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncLithic) -> None:
+ async with async_client.financial_accounts.interest_tier_schedule.with_streaming_response.delete(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ interest_tier_schedule = await response.parse()
+ assert interest_tier_schedule is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_delete(self, async_client: AsyncLithic) -> None:
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `financial_account_token` but received ''"
+ ):
+ await async_client.financial_accounts.interest_tier_schedule.with_raw_response.delete(
+ effective_date=parse_date("2019-12-27"),
+ financial_account_token="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `effective_date` but received ''"):
+ await async_client.financial_accounts.interest_tier_schedule.with_raw_response.delete(
+ effective_date="",
+ financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
diff --git a/tests/api_resources/financial_accounts/test_loan_tape_configuration.py b/tests/api_resources/financial_accounts/test_loan_tape_configuration.py
new file mode 100644
index 00000000..e906241a
--- /dev/null
+++ b/tests/api_resources/financial_accounts/test_loan_tape_configuration.py
@@ -0,0 +1,104 @@
+# 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 lithic import Lithic, AsyncLithic
+from tests.utils import assert_matches_type
+from lithic.types.financial_accounts import LoanTapeConfiguration
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestLoanTapeConfiguration:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_retrieve(self, client: Lithic) -> None:
+ loan_tape_configuration = client.financial_accounts.loan_tape_configuration.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(LoanTapeConfiguration, loan_tape_configuration, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Lithic) -> None:
+ response = client.financial_accounts.loan_tape_configuration.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ loan_tape_configuration = response.parse()
+ assert_matches_type(LoanTapeConfiguration, loan_tape_configuration, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Lithic) -> None:
+ with client.financial_accounts.loan_tape_configuration.with_streaming_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ loan_tape_configuration = response.parse()
+ assert_matches_type(LoanTapeConfiguration, loan_tape_configuration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: Lithic) -> None:
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `financial_account_token` but received ''"
+ ):
+ client.financial_accounts.loan_tape_configuration.with_raw_response.retrieve(
+ "",
+ )
+
+
+class TestAsyncLoanTapeConfiguration:
+ 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: AsyncLithic) -> None:
+ loan_tape_configuration = await async_client.financial_accounts.loan_tape_configuration.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(LoanTapeConfiguration, loan_tape_configuration, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncLithic) -> None:
+ response = await async_client.financial_accounts.loan_tape_configuration.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ loan_tape_configuration = response.parse()
+ assert_matches_type(LoanTapeConfiguration, loan_tape_configuration, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncLithic) -> None:
+ async with async_client.financial_accounts.loan_tape_configuration.with_streaming_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ loan_tape_configuration = await response.parse()
+ assert_matches_type(LoanTapeConfiguration, loan_tape_configuration, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncLithic) -> None:
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `financial_account_token` but received ''"
+ ):
+ await async_client.financial_accounts.loan_tape_configuration.with_raw_response.retrieve(
+ "",
+ )
diff --git a/tests/test_client.py b/tests/test_client.py
index 62647a32..9cbf4688 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -982,6 +982,14 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None:
# Test that the proxy environment variables are set correctly
monkeypatch.setenv("HTTPS_PROXY", "https://example.org")
+ # Delete in case our environment has any proxy env vars set
+ monkeypatch.delenv("HTTP_PROXY", raising=False)
+ monkeypatch.delenv("ALL_PROXY", raising=False)
+ monkeypatch.delenv("NO_PROXY", raising=False)
+ monkeypatch.delenv("http_proxy", raising=False)
+ monkeypatch.delenv("https_proxy", raising=False)
+ monkeypatch.delenv("all_proxy", raising=False)
+ monkeypatch.delenv("no_proxy", raising=False)
client = DefaultHttpxClient()
@@ -1923,6 +1931,14 @@ async def test_get_platform(self) -> None:
async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None:
# Test that the proxy environment variables are set correctly
monkeypatch.setenv("HTTPS_PROXY", "https://example.org")
+ # Delete in case our environment has any proxy env vars set
+ monkeypatch.delenv("HTTP_PROXY", raising=False)
+ monkeypatch.delenv("ALL_PROXY", raising=False)
+ monkeypatch.delenv("NO_PROXY", raising=False)
+ monkeypatch.delenv("http_proxy", raising=False)
+ monkeypatch.delenv("https_proxy", raising=False)
+ monkeypatch.delenv("all_proxy", raising=False)
+ monkeypatch.delenv("no_proxy", raising=False)
client = DefaultAsyncHttpxClient()