diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55f660df..b6a32348 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,10 @@ on: - 'integrated/**' - 'stl-preview-head/**' - 'stl-preview-base/**' + pull_request: + branches-ignore: + - 'stl-preview-head/**' + - 'stl-preview-base/**' jobs: lint: diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c486f6de..91393ed8 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.93.0" + ".": "0.94.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 054543bd..2d0fb2d5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 160 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-025f40c854a9485cf316c9058f9cc5fa37f069add30e409d49ab93f2e166f4fb.yml -openapi_spec_hash: a9391f3a54b8db5d5df40169de8c645c -config_hash: fa3481d1d8505e4157f6cebe93211bd0 +configured_endpoints: 161 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-67859c948e3b903a317f4bd14135c7ee44254d2760068117bab34b7c4058be71.yml +openapi_spec_hash: 23a4716c6168e96f040ac8575582d075 +config_hash: 227ad54062905d4ae964b24cef0505b0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1deb08c8..e7085981 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,41 @@ # Changelog +## 0.94.0 (2025-06-23) + +Full Changelog: [v0.93.0...v0.94.0](https://github.com/lithic-com/lithic-python/compare/v0.93.0...v0.94.0) + +### Features + +* **api:** add CLOSED account state option and UNVERIFIED verification method ([b9b15ca](https://github.com/lithic-com/lithic-python/commit/b9b15ca5320605b194b8ac12a9b7a476b6c90027)) +* **client:** add follow_redirects request option ([35e3181](https://github.com/lithic-com/lithic-python/commit/35e31812c2b8c7a1ff943ec7eccc8496d5dd923e)) +* **client:** add support for aiohttp ([b675627](https://github.com/lithic-com/lithic-python/commit/b675627fd898667a17e37ed036c0a7a1ba4b9d9b)) +* **client:** adds endpoint to register an account number on a Financial Account ([9fec4b1](https://github.com/lithic-com/lithic-python/commit/9fec4b13649f8e8ca11733ed0f9a3d8dc7034834)) +* **client:** adds support for 3DS to Auth Rules ([843f8ef](https://github.com/lithic-com/lithic-python/commit/843f8ef3ef8c09643a2179531886c4b0fecbd325)) + + +### Bug Fixes + +* **client:** correctly parse binary response | stream ([1c23f45](https://github.com/lithic-com/lithic-python/commit/1c23f4513b0fe2d7578844f08da8684bb56e449b)) +* **tests:** fix: tests which call HTTP endpoints directly with the example parameters ([6fbce26](https://github.com/lithic-com/lithic-python/commit/6fbce267364552f360519cd6c58c7cbf324d99de)) + + +### Chores + +* **api:** mark some methods as deprecated ([7cd8d1b](https://github.com/lithic-com/lithic-python/commit/7cd8d1b5a8afcc9754a0c703d0c975999be958f4)) +* **ci:** enable for pull requests ([96f3f23](https://github.com/lithic-com/lithic-python/commit/96f3f2381da359a7c9db41db9b2988d9b731063c)) +* **docs:** grammar improvements ([c8610fe](https://github.com/lithic-com/lithic-python/commit/c8610fed4efbb18a63cabbe75596d001922bce29)) +* **docs:** remove reference to rye shell ([3375bf9](https://github.com/lithic-com/lithic-python/commit/3375bf9b3fc3aaf2349e8c68e310472390339fb1)) +* **internal:** update conftest.py ([3607c50](https://github.com/lithic-com/lithic-python/commit/3607c50cf548acd5fa4587b2e86f6b93fbc924aa)) +* **readme:** update badges ([5a08ed9](https://github.com/lithic-com/lithic-python/commit/5a08ed9d58d64d3998a5837b37f8db71a47951c4)) +* **tests:** add tests for httpx client instantiation & proxies ([5b5cda3](https://github.com/lithic-com/lithic-python/commit/5b5cda365c0c6cbf1a6c440c02c8fd5f71915d24)) +* **tests:** run tests in parallel ([62bce48](https://github.com/lithic-com/lithic-python/commit/62bce4878f34851b7f3e7938e6f702ac176b278a)) +* **tests:** skip some failing tests on the latest python versions ([45e57bc](https://github.com/lithic-com/lithic-python/commit/45e57bc33bafb6c2dd7f14d492ee3265c37b8cc2)) + + +### Documentation + +* **client:** fix httpx.Timeout documentation reference ([6df47f4](https://github.com/lithic-com/lithic-python/commit/6df47f4032acaab9c51f29193b8114885dffbcc6)) + ## 0.93.0 (2025-05-15) Full Changelog: [v0.92.0...v0.93.0](https://github.com/lithic-com/lithic-python/compare/v0.92.0...v0.93.0) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d0b5db1c..d68a8975 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,8 +17,7 @@ $ rye sync --all-features You can then run scripts using `rye run python script.py` or by activating the virtual environment: ```sh -$ rye shell -# or manually activate - https://docs.python.org/3/library/venv.html#how-venvs-work +# Activate the virtual environment - https://docs.python.org/3/library/venv.html#how-venvs-work $ source .venv/bin/activate # now you can omit the `rye run` prefix diff --git a/README.md b/README.md index ab54834e..7cd3ca21 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Lithic Python API library -[![PyPI version](https://img.shields.io/pypi/v/lithic.svg)](https://pypi.org/project/lithic/) +[![PyPI version]()](https://pypi.org/project/lithic/) The Lithic Python library provides convenient access to the Lithic REST API from any Python 3.8+ application. The library includes type definitions for all request params and response fields, @@ -70,6 +70,40 @@ asyncio.run(main()) Functionality between the synchronous and asynchronous clients is otherwise identical. +### With aiohttp + +By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend. + +You can enable this by installing `aiohttp`: + +```sh +# install from PyPI +pip install lithic[aiohttp] +``` + +Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: + +```python +import os +import asyncio +from lithic import DefaultAioHttpClient +from lithic import AsyncLithic + + +async def main() -> None: + async with AsyncLithic( + api_key=os.environ.get("LITHIC_API_KEY"), # This is the default and can be omitted + http_client=DefaultAioHttpClient(), + ) as client: + card = await client.cards.create( + type="SINGLE_USE", + ) + print(card.token) + + +asyncio.run(main()) +``` + ## Using types Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like: @@ -234,7 +268,7 @@ client.with_options(max_retries=5).cards.list( ### Timeouts By default requests time out after 1 minute. You can configure this with a `timeout` option, -which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object: +which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object: ```python from lithic import Lithic diff --git a/SECURITY.md b/SECURITY.md index eae5ea4d..d586eacc 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,11 +16,11 @@ before making any information public. ## Reporting Non-SDK Related Security Issues If you encounter security issues that are not directly related to SDKs but pertain to the services -or products provided by Lithic please follow the respective company's security reporting guidelines. +or products provided by Lithic, please follow the respective company's security reporting guidelines. ### Lithic Terms and Policies -Please contact sdk-feedback@lithic.com for any questions or concerns regarding security of our services. +Please contact sdk-feedback@lithic.com for any questions or concerns regarding the security of our services. --- diff --git a/api.md b/api.md index 12536aa0..323fabf8 100644 --- a/api.md +++ b/api.md @@ -338,6 +338,7 @@ Methods: - client.financial_accounts.retrieve(financial_account_token) -> FinancialAccount - client.financial_accounts.update(financial_account_token, \*\*params) -> FinancialAccount - client.financial_accounts.list(\*\*params) -> SyncSinglePage[FinancialAccount] +- client.financial_accounts.register_account_number(financial_account_token, \*\*params) -> None - client.financial_accounts.update_status(financial_account_token, \*\*params) -> FinancialAccount ## Balances diff --git a/pyproject.toml b/pyproject.toml index 29217aae..71756fe2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "lithic" -version = "0.93.0" +version = "0.94.0" description = "The official Python library for the lithic API" dynamic = ["readme"] license = "Apache-2.0" @@ -37,6 +37,8 @@ classifiers = [ Homepage = "https://github.com/lithic-com/lithic-python" Repository = "https://github.com/lithic-com/lithic-python" +[project.optional-dependencies] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.6"] [tool.rye] managed = true @@ -54,6 +56,7 @@ dev-dependencies = [ "importlib-metadata>=6.7.0", "rich>=13.7.1", "nest_asyncio==1.6.0", + "pytest-xdist>=3.6.1", ] [tool.rye.scripts] @@ -125,7 +128,7 @@ replacement = '[\1](https://github.com/lithic-com/lithic-python/tree/main/\g<2>) [tool.pytest.ini_options] testpaths = ["tests"] -addopts = "--tb=short" +addopts = "--tb=short -n auto" xfail_strict = true asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "session" diff --git a/requirements-dev.lock b/requirements-dev.lock index e0d8eb25..5e2eddce 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -10,6 +10,13 @@ # universal: false -e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.8 + # via httpx-aiohttp + # via lithic +aiosignal==1.3.2 + # via aiohttp annotated-types==0.6.0 # via pydantic anyio==4.4.0 @@ -17,6 +24,10 @@ anyio==4.4.0 # via lithic argcomplete==3.1.2 # via nox +async-timeout==5.0.1 + # via aiohttp +attrs==25.3.0 + # via aiohttp certifi==2023.7.22 # via httpcore # via httpx @@ -30,18 +41,27 @@ distro==1.8.0 exceptiongroup==1.2.2 # via anyio # via pytest +execnet==2.1.1 + # via pytest-xdist filelock==3.12.4 # via virtualenv +frozenlist==1.6.2 + # via aiohttp + # via aiosignal h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx httpx==0.28.1 + # via httpx-aiohttp # via lithic # via respx +httpx-aiohttp==0.1.6 + # via lithic idna==3.4 # via anyio # via httpx + # via yarl importlib-metadata==7.0.0 iniconfig==2.0.0 # via pytest @@ -49,6 +69,9 @@ markdown-it-py==3.0.0 # via rich mdurl==0.1.2 # via markdown-it-py +multidict==6.4.4 + # via aiohttp + # via yarl mypy==1.14.1 mypy-extensions==1.0.0 # via mypy @@ -63,6 +86,9 @@ platformdirs==3.11.0 # via virtualenv pluggy==1.5.0 # via pytest +propcache==0.3.1 + # via aiohttp + # via yarl pydantic==2.10.3 # via lithic pydantic-core==2.27.1 @@ -72,7 +98,9 @@ pygments==2.18.0 pyright==1.1.399 pytest==8.3.3 # via pytest-asyncio + # via pytest-xdist pytest-asyncio==0.24.0 +pytest-xdist==3.7.0 python-dateutil==2.8.2 # via time-machine pytz==2023.3.post1 @@ -94,11 +122,14 @@ tomli==2.0.2 typing-extensions==4.12.2 # via anyio # via lithic + # via multidict # via mypy # via pydantic # via pydantic-core # via pyright virtualenv==20.24.5 # via nox +yarl==1.20.0 + # via aiohttp zipp==3.17.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index 0745afc3..d849a86d 100644 --- a/requirements.lock +++ b/requirements.lock @@ -10,11 +10,22 @@ # universal: false -e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.8 + # via httpx-aiohttp + # via lithic +aiosignal==1.3.2 + # via aiohttp annotated-types==0.6.0 # via pydantic anyio==4.4.0 # via httpx # via lithic +async-timeout==5.0.1 + # via aiohttp +attrs==25.3.0 + # via aiohttp certifi==2023.7.22 # via httpcore # via httpx @@ -22,15 +33,28 @@ distro==1.8.0 # via lithic exceptiongroup==1.2.2 # via anyio +frozenlist==1.6.2 + # via aiohttp + # via aiosignal h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx httpx==0.28.1 + # via httpx-aiohttp + # via lithic +httpx-aiohttp==0.1.6 # via lithic idna==3.4 # via anyio # via httpx + # via yarl +multidict==6.4.4 + # via aiohttp + # via yarl +propcache==0.3.1 + # via aiohttp + # via yarl pydantic==2.10.3 # via lithic pydantic-core==2.27.1 @@ -41,5 +65,8 @@ sniffio==1.3.0 typing-extensions==4.12.2 # via anyio # via lithic + # via multidict # via pydantic # via pydantic-core +yarl==1.20.0 + # via aiohttp diff --git a/src/lithic/__init__.py b/src/lithic/__init__.py index 155e7648..30958967 100644 --- a/src/lithic/__init__.py +++ b/src/lithic/__init__.py @@ -37,7 +37,7 @@ UnprocessableEntityError, APIResponseValidationError, ) -from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient +from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient from ._utils._logs import setup_logging as _setup_logging __all__ = [ @@ -80,6 +80,7 @@ "DEFAULT_CONNECTION_LIMITS", "DefaultHttpxClient", "DefaultAsyncHttpxClient", + "DefaultAioHttpClient", ] if not _t.TYPE_CHECKING: diff --git a/src/lithic/_base_client.py b/src/lithic/_base_client.py index b9890312..fc52e763 100644 --- a/src/lithic/_base_client.py +++ b/src/lithic/_base_client.py @@ -961,6 +961,9 @@ def request( if self.custom_auth is not None: kwargs["auth"] = self.custom_auth + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects + log.debug("Sending HTTP Request: %s %s", request.method, request.url) response = None @@ -1083,7 +1086,14 @@ def _process_response( origin = get_origin(cast_to) or cast_to - if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse): + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): if not issubclass(origin, APIResponse): raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}") @@ -1294,6 +1304,24 @@ def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) +try: + import httpx_aiohttp +except ImportError: + + class _DefaultAioHttpClient(httpx.AsyncClient): + def __init__(self, **_kwargs: Any) -> None: + raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra") +else: + + class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + + super().__init__(**kwargs) + + if TYPE_CHECKING: DefaultAsyncHttpxClient = httpx.AsyncClient """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK @@ -1302,8 +1330,12 @@ def __init__(self, **kwargs: Any) -> None: This is useful because overriding the `http_client` with your own instance of `httpx.AsyncClient` will result in httpx's defaults being used, not ours. """ + + DefaultAioHttpClient = httpx.AsyncClient + """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`.""" else: DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient + DefaultAioHttpClient = _DefaultAioHttpClient class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): @@ -1475,6 +1507,9 @@ async def request( if self.custom_auth is not None: kwargs["auth"] = self.custom_auth + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects + log.debug("Sending HTTP Request: %s %s", request.method, request.url) response = None @@ -1597,7 +1632,14 @@ async def _process_response( origin = get_origin(cast_to) or cast_to - if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse): + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): if not issubclass(origin, AsyncAPIResponse): raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}") diff --git a/src/lithic/_models.py b/src/lithic/_models.py index 798956f1..4f214980 100644 --- a/src/lithic/_models.py +++ b/src/lithic/_models.py @@ -737,6 +737,7 @@ class FinalRequestOptionsInput(TypedDict, total=False): idempotency_key: str json_data: Body extra_json: AnyMapping + follow_redirects: bool @final @@ -750,6 +751,7 @@ class FinalRequestOptions(pydantic.BaseModel): files: Union[HttpxRequestFiles, None] = None idempotency_key: Union[str, None] = None post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() + follow_redirects: Union[bool, None] = None # It should be noted that we cannot use `json` here as that would override # a BaseModel method in an incompatible fashion. diff --git a/src/lithic/_types.py b/src/lithic/_types.py index 3cb9cf06..8100439c 100644 --- a/src/lithic/_types.py +++ b/src/lithic/_types.py @@ -101,6 +101,7 @@ class RequestOptions(TypedDict, total=False): params: Query extra_json: AnyMapping idempotency_key: str + follow_redirects: bool # Sentinel class used until PEP 0661 is accepted @@ -217,3 +218,4 @@ class _GenericAlias(Protocol): class HttpxSendArgs(TypedDict, total=False): auth: httpx.Auth + follow_redirects: bool diff --git a/src/lithic/_version.py b/src/lithic/_version.py index 284c0a6a..7cfff106 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.93.0" # x-release-please-version +__version__ = "0.94.0" # x-release-please-version diff --git a/src/lithic/resources/accounts.py b/src/lithic/resources/accounts.py index 1fc7c88b..87d69eb8 100644 --- a/src/lithic/resources/accounts.py +++ b/src/lithic/resources/accounts.py @@ -83,7 +83,7 @@ def update( daily_spend_limit: int | NotGiven = NOT_GIVEN, lifetime_spend_limit: int | NotGiven = NOT_GIVEN, monthly_spend_limit: int | NotGiven = NOT_GIVEN, - state: Literal["ACTIVE", "PAUSED"] | NotGiven = NOT_GIVEN, + state: Literal["ACTIVE", "PAUSED", "CLOSED"] | NotGiven = NOT_GIVEN, verification_address: account_update_params.VerificationAddress | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -117,8 +117,8 @@ def update( verification_address: Address used during Address Verification Service (AVS) checks during transactions if enabled via Auth Rules. This field is deprecated as AVS checks - are no longer supported by Authorization Rules. The field will be removed from - the schema in a future release. + are no longer supported by Auth Rules. The field will be removed from the schema + in a future release. extra_headers: Send extra headers @@ -310,7 +310,7 @@ async def update( daily_spend_limit: int | NotGiven = NOT_GIVEN, lifetime_spend_limit: int | NotGiven = NOT_GIVEN, monthly_spend_limit: int | NotGiven = NOT_GIVEN, - state: Literal["ACTIVE", "PAUSED"] | NotGiven = NOT_GIVEN, + state: Literal["ACTIVE", "PAUSED", "CLOSED"] | NotGiven = NOT_GIVEN, verification_address: account_update_params.VerificationAddress | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -344,8 +344,8 @@ async def update( verification_address: Address used during Address Verification Service (AVS) checks during transactions if enabled via Auth Rules. This field is deprecated as AVS checks - are no longer supported by Authorization Rules. The field will be removed from - the schema in a future release. + are no longer supported by Auth Rules. The field will be removed from the schema + in a future release. extra_headers: Send extra headers diff --git a/src/lithic/resources/auth_rules/v2/backtests.py b/src/lithic/resources/auth_rules/v2/backtests.py index 7a721a9f..ae5e9db0 100644 --- a/src/lithic/resources/auth_rules/v2/backtests.py +++ b/src/lithic/resources/auth_rules/v2/backtests.py @@ -55,16 +55,15 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> BacktestCreateResponse: """ - Initiates a request to asynchronously generate a backtest for an authorization - rule. During backtesting, both the active version (if one exists) and the draft - version of the Authorization Rule are evaluated by replaying historical - transaction data against the rule's conditions. This process allows customers to - simulate and understand the effects of proposed rule changes before deployment. - The generated backtest report provides detailed results showing whether the - draft version of the Auth Rule would have approved or declined historical - transactions which were processed during the backtest period. These reports help - evaluate how changes to rule configurations might affect overall transaction - approval rates. + Initiates a request to asynchronously generate a backtest for an Auth rule. + During backtesting, both the active version (if one exists) and the draft + version of the Auth Rule are evaluated by replaying historical transaction data + against the rule's conditions. This process allows customers to simulate and + understand the effects of proposed rule changes before deployment. The generated + backtest report provides detailed results showing whether the draft version of + the Auth Rule would have approved or declined historical transactions which were + processed during the backtest period. These reports help evaluate how changes to + rule configurations might affect overall transaction approval rates. The generated backtest report will be delivered asynchronously through a webhook with `event_type` = `auth_rules.backtest_report.created`. See the docs on @@ -124,7 +123,7 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> BacktestResults: """ - Returns the backtest results of an authorization rule (if available). + Returns the backtest results of an Auth rule (if available). Backtesting is an asynchronous process that requires time to complete. If a customer retrieves the backtest results using this endpoint before the report is @@ -140,8 +139,8 @@ def retrieve( also always represent the configuration of the rule at the time requests are made to this endpoint. For example, the results for `current_version` in the served backtest report will be consistent with which version of the rule is - currently activated in the Auth Stream, regardless of which version of the rule - was active in the Auth Stream at the time a backtest is requested. + currently activated in the respective event stream, regardless of which version + of the rule was active in the event stream at the time a backtest is requested. Args: extra_headers: Send extra headers @@ -201,16 +200,15 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> BacktestCreateResponse: """ - Initiates a request to asynchronously generate a backtest for an authorization - rule. During backtesting, both the active version (if one exists) and the draft - version of the Authorization Rule are evaluated by replaying historical - transaction data against the rule's conditions. This process allows customers to - simulate and understand the effects of proposed rule changes before deployment. - The generated backtest report provides detailed results showing whether the - draft version of the Auth Rule would have approved or declined historical - transactions which were processed during the backtest period. These reports help - evaluate how changes to rule configurations might affect overall transaction - approval rates. + Initiates a request to asynchronously generate a backtest for an Auth rule. + During backtesting, both the active version (if one exists) and the draft + version of the Auth Rule are evaluated by replaying historical transaction data + against the rule's conditions. This process allows customers to simulate and + understand the effects of proposed rule changes before deployment. The generated + backtest report provides detailed results showing whether the draft version of + the Auth Rule would have approved or declined historical transactions which were + processed during the backtest period. These reports help evaluate how changes to + rule configurations might affect overall transaction approval rates. The generated backtest report will be delivered asynchronously through a webhook with `event_type` = `auth_rules.backtest_report.created`. See the docs on @@ -270,7 +268,7 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> BacktestResults: """ - Returns the backtest results of an authorization rule (if available). + Returns the backtest results of an Auth rule (if available). Backtesting is an asynchronous process that requires time to complete. If a customer retrieves the backtest results using this endpoint before the report is @@ -286,8 +284,8 @@ async def retrieve( also always represent the configuration of the rule at the time requests are made to this endpoint. For example, the results for `current_version` in the served backtest report will be consistent with which version of the rule is - currently activated in the Auth Stream, regardless of which version of the rule - was active in the Auth Stream at the time a backtest is requested. + currently activated in the respective event stream, regardless of which version + of the rule was active in the event stream at the time a backtest is requested. Args: extra_headers: Send extra headers diff --git a/src/lithic/resources/auth_rules/v2/v2.py b/src/lithic/resources/auth_rules/v2/v2.py index 52f73ea6..fd793e41 100644 --- a/src/lithic/resources/auth_rules/v2/v2.py +++ b/src/lithic/resources/auth_rules/v2/v2.py @@ -2,6 +2,7 @@ from __future__ import annotations +import typing_extensions from typing import List, Optional from typing_extensions import Literal, overload @@ -67,7 +68,8 @@ def create( account_tokens: List[str], name: Optional[str] | NotGiven = NOT_GIVEN, parameters: v2_create_params.CreateAuthRuleRequestAccountTokensParameters | NotGiven = NOT_GIVEN, - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] | NotGiven = NOT_GIVEN, + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -76,7 +78,7 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2CreateResponse: """ - Creates a new V2 authorization rule in draft mode + Creates a new V2 Auth rule in draft mode Args: account_tokens: Account tokens to which the Auth Rule applies. @@ -85,7 +87,13 @@ def create( parameters: Parameters for the Auth Rule - type: The type of Auth Rule + type: The type of Auth Rule. Effectively determines the event stream during which it + will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. extra_headers: Send extra headers @@ -104,7 +112,8 @@ def create( card_tokens: List[str], name: Optional[str] | NotGiven = NOT_GIVEN, parameters: v2_create_params.CreateAuthRuleRequestCardTokensParameters | NotGiven = NOT_GIVEN, - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] | NotGiven = NOT_GIVEN, + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -113,7 +122,7 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2CreateResponse: """ - Creates a new V2 authorization rule in draft mode + Creates a new V2 Auth rule in draft mode Args: card_tokens: Card tokens to which the Auth Rule applies. @@ -122,7 +131,13 @@ def create( parameters: Parameters for the Auth Rule - type: The type of Auth Rule + type: The type of Auth Rule. Effectively determines the event stream during which it + will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. extra_headers: Send extra headers @@ -142,7 +157,8 @@ def create( excluded_card_tokens: List[str] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, parameters: v2_create_params.CreateAuthRuleRequestProgramLevelParameters | NotGiven = NOT_GIVEN, - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] | NotGiven = NOT_GIVEN, + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -151,7 +167,7 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2CreateResponse: """ - Creates a new V2 authorization rule in draft mode + Creates a new V2 Auth rule in draft mode Args: program_level: Whether the Auth Rule applies to all authorizations on the card program. @@ -162,7 +178,13 @@ def create( parameters: Parameters for the Auth Rule - type: The type of Auth Rule + type: The type of Auth Rule. Effectively determines the event stream during which it + will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. extra_headers: Send extra headers @@ -181,7 +203,8 @@ def create( account_tokens: List[str] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, parameters: v2_create_params.CreateAuthRuleRequestAccountTokensParameters | NotGiven = NOT_GIVEN, - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] | NotGiven = NOT_GIVEN, + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + | NotGiven = NOT_GIVEN, card_tokens: List[str] | NotGiven = NOT_GIVEN, program_level: bool | NotGiven = NOT_GIVEN, excluded_card_tokens: List[str] | NotGiven = NOT_GIVEN, @@ -224,7 +247,7 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2RetrieveResponse: """ - Fetches a V2 authorization rule by its token + Fetches a V2 Auth rule by its token Args: extra_headers: Send extra headers @@ -261,7 +284,7 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2UpdateResponse: """ - Updates a V2 authorization rule's properties + Updates a V2 Auth rule's properties If `account_tokens`, `card_tokens`, `program_level`, or `excluded_card_tokens` is provided, this will replace existing associations with the provided list of @@ -304,7 +327,7 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2UpdateResponse: """ - Updates a V2 authorization rule's properties + Updates a V2 Auth rule's properties If `account_tokens`, `card_tokens`, `program_level`, or `excluded_card_tokens` is provided, this will replace existing associations with the provided list of @@ -348,7 +371,7 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2UpdateResponse: """ - Updates a V2 authorization rule's properties + Updates a V2 Auth rule's properties If `account_tokens`, `card_tokens`, `program_level`, or `excluded_card_tokens` is provided, this will replace existing associations with the provided list of @@ -421,6 +444,7 @@ def list( account_token: str | NotGiven = NOT_GIVEN, card_token: str | NotGiven = NOT_GIVEN, ending_before: str | NotGiven = NOT_GIVEN, + event_stream: Literal["AUTHORIZATION", "THREE_DS_AUTHENTICATION"] | NotGiven = NOT_GIVEN, page_size: int | NotGiven = NOT_GIVEN, scope: Literal["PROGRAM", "ACCOUNT", "CARD"] | NotGiven = NOT_GIVEN, starting_after: str | NotGiven = NOT_GIVEN, @@ -432,19 +456,21 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> SyncCursorPage[V2ListResponse]: """ - Lists V2 authorization rules + Lists V2 Auth rules Args: - account_token: Only return Authorization Rules that are bound to the provided account token. + account_token: Only return Auth Rules that are bound to the provided account token. - card_token: Only return Authorization Rules that are bound to the provided card token. + card_token: Only return Auth Rules that are bound to the provided card token. ending_before: A cursor representing an item's token before which a page of results should end. Used to retrieve the previous page of results before this item. + event_stream: Only return Auth rules that are executed during the provided event stream. + page_size: Page size (for pagination). - scope: Only return Authorization Rules that are bound to the provided scope; + scope: Only return Auth Rules that are bound to the provided scope. starting_after: A cursor representing an item's token after which a page of results should begin. Used to retrieve the next page of results after this item. @@ -470,6 +496,7 @@ def list( "account_token": account_token, "card_token": card_token, "ending_before": ending_before, + "event_stream": event_stream, "page_size": page_size, "scope": scope, "starting_after": starting_after, @@ -492,7 +519,7 @@ def delete( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> None: """ - Deletes a V2 authorization rule + Deletes a V2 Auth rule Args: extra_headers: Send extra headers @@ -513,6 +540,7 @@ def delete( cast_to=NoneType, ) + @typing_extensions.deprecated("deprecated") @overload def apply( self, @@ -527,8 +555,8 @@ def apply( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2ApplyResponse: """ - Associates a V2 authorization rule with a card program, the provided account(s) - or card(s). + Associates a V2 Auth rule with a card program, the provided account(s) or + card(s). Prefer using the `PATCH` method for this operation. @@ -545,6 +573,7 @@ def apply( """ ... + @typing_extensions.deprecated("deprecated") @overload def apply( self, @@ -559,8 +588,8 @@ def apply( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2ApplyResponse: """ - Associates a V2 authorization rule with a card program, the provided account(s) - or card(s). + Associates a V2 Auth rule with a card program, the provided account(s) or + card(s). Prefer using the `PATCH` method for this operation. @@ -577,6 +606,7 @@ def apply( """ ... + @typing_extensions.deprecated("deprecated") @overload def apply( self, @@ -592,8 +622,8 @@ def apply( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2ApplyResponse: """ - Associates a V2 authorization rule with a card program, the provided account(s) - or card(s). + Associates a V2 Auth rule with a card program, the provided account(s) or + card(s). Prefer using the `PATCH` method for this operation. @@ -612,6 +642,7 @@ def apply( """ ... + @typing_extensions.deprecated("deprecated") @required_args(["account_tokens"], ["card_tokens"], ["program_level"]) def apply( self, @@ -699,8 +730,8 @@ def promote( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2PromoteResponse: """ - Promotes the draft version of an authorization rule to the currently active - version such that it is enforced in the authorization stream. + Promotes the draft version of an Auth rule to the currently active version such + that it is enforced in the respective stream. Args: extra_headers: Send extra headers @@ -733,26 +764,25 @@ def report( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2ReportResponse: """ - Requests a performance report of an authorization rule to be asynchronously - generated. Reports can only be run on rules in draft or active mode and will - included approved and declined statistics as well as examples. The generated - report will be delivered asynchronously through a webhook with `event_type` = + Requests a performance report of an Auth rule to be asynchronously generated. + Reports can only be run on rules in draft or active mode and will included + approved and declined statistics as well as examples. The generated report will + be delivered asynchronously through a webhook with `event_type` = `auth_rules.performance_report.created`. See the docs on setting up [webhook subscriptions](https://docs.lithic.com/docs/events-api). - Reports are generated based on data collected by Lithic's authorization - processing system in the trailing week. The performance of the auth rule will be - assessed on the configuration of the auth rule at the time the report is - requested. This implies that if a performance report is requested, right after - updating an auth rule, depending on the number of authorizations processed for a - card program, it may be the case that no data is available for the report. - Therefore Lithic recommends to decouple making updates to an Auth Rule, and - requesting performance reports. + Reports are generated based on data collected by Lithic's processing system in + the trailing week. The performance of the auth rule will be assessed on the + configuration of the auth rule at the time the report is requested. This implies + that if a performance report is requested, right after updating an auth rule, + depending on the number of events processed for a card program, it may be the + case that no data is available for the report. Therefore Lithic recommends to + decouple making updates to an Auth Rule, and requesting performance reports. To make this concrete, consider the following example: - 1. At time `t`, a new Auth Rule is created, and applies to all authorizations on - a card program. The Auth Rule has not yet been promoted, causing the draft + 1. At time `t`, a new Auth Rule is created, and applies to all auth events on a + card program. The Auth Rule has not yet been promoted, causing the draft version of the rule to be applied in shadow mode. 2. At time `t + 1 hour` a performance report is requested for the Auth Rule. This performance report will _only_ contain data for the Auth Rule being @@ -767,17 +797,17 @@ def report( `t + 2 hours`. 4. At time `t + 3 hours` a new version of the rule is drafted by calling the `/v2/auth_rules/{auth_rule_token}/draft` endpoint. If a performance report is - requested right at this moment, it will only contain data for authorizations - to which both the active version and the draft version is applied. Lithic - does this to ensure that performance reports represent a fair comparison - between rules. Because there may be no authorizations in this window, and - because there may be some lag before data is available in a performance - report, the requested performance report could contain no to little data. + requested right at this moment, it will only contain data for events to which + both the active version and the draft version is applied. Lithic does this to + ensure that performance reports represent a fair comparison between rules. + Because there may be no events in this window, and because there may be some + lag before data is available in a performance report, the requested + performance report could contain no to little data. 5. At time `t + 4 hours` another performance report is requested: this time the performance report will contain data from the window between `t + 3 hours` - and `t + 4 hours`, for any authorizations to which both the current version - of the authorization rule (in enforcing mode) and the draft version of the - authorization rule (in shadow mode) applied. + and `t + 4 hours`, for any events to which both the current version of the + Auth rule (in enforcing mode) and the draft version of the Auth rule (in + shadow mode) applied. Note that generating a report may take up to 15 minutes and that delivery is not guaranteed. Customers are required to have created an event subscription to @@ -836,7 +866,8 @@ async def create( account_tokens: List[str], name: Optional[str] | NotGiven = NOT_GIVEN, parameters: v2_create_params.CreateAuthRuleRequestAccountTokensParameters | NotGiven = NOT_GIVEN, - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] | NotGiven = NOT_GIVEN, + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -845,7 +876,7 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2CreateResponse: """ - Creates a new V2 authorization rule in draft mode + Creates a new V2 Auth rule in draft mode Args: account_tokens: Account tokens to which the Auth Rule applies. @@ -854,7 +885,13 @@ async def create( parameters: Parameters for the Auth Rule - type: The type of Auth Rule + type: The type of Auth Rule. Effectively determines the event stream during which it + will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. extra_headers: Send extra headers @@ -873,7 +910,8 @@ async def create( card_tokens: List[str], name: Optional[str] | NotGiven = NOT_GIVEN, parameters: v2_create_params.CreateAuthRuleRequestCardTokensParameters | NotGiven = NOT_GIVEN, - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] | NotGiven = NOT_GIVEN, + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -882,7 +920,7 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2CreateResponse: """ - Creates a new V2 authorization rule in draft mode + Creates a new V2 Auth rule in draft mode Args: card_tokens: Card tokens to which the Auth Rule applies. @@ -891,7 +929,13 @@ async def create( parameters: Parameters for the Auth Rule - type: The type of Auth Rule + type: The type of Auth Rule. Effectively determines the event stream during which it + will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. extra_headers: Send extra headers @@ -911,7 +955,8 @@ async def create( excluded_card_tokens: List[str] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, parameters: v2_create_params.CreateAuthRuleRequestProgramLevelParameters | NotGiven = NOT_GIVEN, - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] | NotGiven = NOT_GIVEN, + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -920,7 +965,7 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2CreateResponse: """ - Creates a new V2 authorization rule in draft mode + Creates a new V2 Auth rule in draft mode Args: program_level: Whether the Auth Rule applies to all authorizations on the card program. @@ -931,7 +976,13 @@ async def create( parameters: Parameters for the Auth Rule - type: The type of Auth Rule + type: The type of Auth Rule. Effectively determines the event stream during which it + will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. extra_headers: Send extra headers @@ -950,7 +1001,8 @@ async def create( account_tokens: List[str] | NotGiven = NOT_GIVEN, name: Optional[str] | NotGiven = NOT_GIVEN, parameters: v2_create_params.CreateAuthRuleRequestAccountTokensParameters | NotGiven = NOT_GIVEN, - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] | NotGiven = NOT_GIVEN, + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + | NotGiven = NOT_GIVEN, card_tokens: List[str] | NotGiven = NOT_GIVEN, program_level: bool | NotGiven = NOT_GIVEN, excluded_card_tokens: List[str] | NotGiven = NOT_GIVEN, @@ -993,7 +1045,7 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2RetrieveResponse: """ - Fetches a V2 authorization rule by its token + Fetches a V2 Auth rule by its token Args: extra_headers: Send extra headers @@ -1030,7 +1082,7 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2UpdateResponse: """ - Updates a V2 authorization rule's properties + Updates a V2 Auth rule's properties If `account_tokens`, `card_tokens`, `program_level`, or `excluded_card_tokens` is provided, this will replace existing associations with the provided list of @@ -1073,7 +1125,7 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2UpdateResponse: """ - Updates a V2 authorization rule's properties + Updates a V2 Auth rule's properties If `account_tokens`, `card_tokens`, `program_level`, or `excluded_card_tokens` is provided, this will replace existing associations with the provided list of @@ -1117,7 +1169,7 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2UpdateResponse: """ - Updates a V2 authorization rule's properties + Updates a V2 Auth rule's properties If `account_tokens`, `card_tokens`, `program_level`, or `excluded_card_tokens` is provided, this will replace existing associations with the provided list of @@ -1190,6 +1242,7 @@ def list( account_token: str | NotGiven = NOT_GIVEN, card_token: str | NotGiven = NOT_GIVEN, ending_before: str | NotGiven = NOT_GIVEN, + event_stream: Literal["AUTHORIZATION", "THREE_DS_AUTHENTICATION"] | NotGiven = NOT_GIVEN, page_size: int | NotGiven = NOT_GIVEN, scope: Literal["PROGRAM", "ACCOUNT", "CARD"] | NotGiven = NOT_GIVEN, starting_after: str | NotGiven = NOT_GIVEN, @@ -1201,19 +1254,21 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> AsyncPaginator[V2ListResponse, AsyncCursorPage[V2ListResponse]]: """ - Lists V2 authorization rules + Lists V2 Auth rules Args: - account_token: Only return Authorization Rules that are bound to the provided account token. + account_token: Only return Auth Rules that are bound to the provided account token. - card_token: Only return Authorization Rules that are bound to the provided card token. + card_token: Only return Auth Rules that are bound to the provided card token. ending_before: A cursor representing an item's token before which a page of results should end. Used to retrieve the previous page of results before this item. + event_stream: Only return Auth rules that are executed during the provided event stream. + page_size: Page size (for pagination). - scope: Only return Authorization Rules that are bound to the provided scope; + scope: Only return Auth Rules that are bound to the provided scope. starting_after: A cursor representing an item's token after which a page of results should begin. Used to retrieve the next page of results after this item. @@ -1239,6 +1294,7 @@ def list( "account_token": account_token, "card_token": card_token, "ending_before": ending_before, + "event_stream": event_stream, "page_size": page_size, "scope": scope, "starting_after": starting_after, @@ -1261,7 +1317,7 @@ async def delete( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> None: """ - Deletes a V2 authorization rule + Deletes a V2 Auth rule Args: extra_headers: Send extra headers @@ -1282,6 +1338,7 @@ async def delete( cast_to=NoneType, ) + @typing_extensions.deprecated("deprecated") @overload async def apply( self, @@ -1296,8 +1353,8 @@ async def apply( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2ApplyResponse: """ - Associates a V2 authorization rule with a card program, the provided account(s) - or card(s). + Associates a V2 Auth rule with a card program, the provided account(s) or + card(s). Prefer using the `PATCH` method for this operation. @@ -1314,6 +1371,7 @@ async def apply( """ ... + @typing_extensions.deprecated("deprecated") @overload async def apply( self, @@ -1328,8 +1386,8 @@ async def apply( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2ApplyResponse: """ - Associates a V2 authorization rule with a card program, the provided account(s) - or card(s). + Associates a V2 Auth rule with a card program, the provided account(s) or + card(s). Prefer using the `PATCH` method for this operation. @@ -1346,6 +1404,7 @@ async def apply( """ ... + @typing_extensions.deprecated("deprecated") @overload async def apply( self, @@ -1361,8 +1420,8 @@ async def apply( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2ApplyResponse: """ - Associates a V2 authorization rule with a card program, the provided account(s) - or card(s). + Associates a V2 Auth rule with a card program, the provided account(s) or + card(s). Prefer using the `PATCH` method for this operation. @@ -1381,6 +1440,7 @@ async def apply( """ ... + @typing_extensions.deprecated("deprecated") @required_args(["account_tokens"], ["card_tokens"], ["program_level"]) async def apply( self, @@ -1468,8 +1528,8 @@ async def promote( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2PromoteResponse: """ - Promotes the draft version of an authorization rule to the currently active - version such that it is enforced in the authorization stream. + Promotes the draft version of an Auth rule to the currently active version such + that it is enforced in the respective stream. Args: extra_headers: Send extra headers @@ -1502,26 +1562,25 @@ async def report( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2ReportResponse: """ - Requests a performance report of an authorization rule to be asynchronously - generated. Reports can only be run on rules in draft or active mode and will - included approved and declined statistics as well as examples. The generated - report will be delivered asynchronously through a webhook with `event_type` = + Requests a performance report of an Auth rule to be asynchronously generated. + Reports can only be run on rules in draft or active mode and will included + approved and declined statistics as well as examples. The generated report will + be delivered asynchronously through a webhook with `event_type` = `auth_rules.performance_report.created`. See the docs on setting up [webhook subscriptions](https://docs.lithic.com/docs/events-api). - Reports are generated based on data collected by Lithic's authorization - processing system in the trailing week. The performance of the auth rule will be - assessed on the configuration of the auth rule at the time the report is - requested. This implies that if a performance report is requested, right after - updating an auth rule, depending on the number of authorizations processed for a - card program, it may be the case that no data is available for the report. - Therefore Lithic recommends to decouple making updates to an Auth Rule, and - requesting performance reports. + Reports are generated based on data collected by Lithic's processing system in + the trailing week. The performance of the auth rule will be assessed on the + configuration of the auth rule at the time the report is requested. This implies + that if a performance report is requested, right after updating an auth rule, + depending on the number of events processed for a card program, it may be the + case that no data is available for the report. Therefore Lithic recommends to + decouple making updates to an Auth Rule, and requesting performance reports. To make this concrete, consider the following example: - 1. At time `t`, a new Auth Rule is created, and applies to all authorizations on - a card program. The Auth Rule has not yet been promoted, causing the draft + 1. At time `t`, a new Auth Rule is created, and applies to all auth events on a + card program. The Auth Rule has not yet been promoted, causing the draft version of the rule to be applied in shadow mode. 2. At time `t + 1 hour` a performance report is requested for the Auth Rule. This performance report will _only_ contain data for the Auth Rule being @@ -1536,17 +1595,17 @@ async def report( `t + 2 hours`. 4. At time `t + 3 hours` a new version of the rule is drafted by calling the `/v2/auth_rules/{auth_rule_token}/draft` endpoint. If a performance report is - requested right at this moment, it will only contain data for authorizations - to which both the active version and the draft version is applied. Lithic - does this to ensure that performance reports represent a fair comparison - between rules. Because there may be no authorizations in this window, and - because there may be some lag before data is available in a performance - report, the requested performance report could contain no to little data. + requested right at this moment, it will only contain data for events to which + both the active version and the draft version is applied. Lithic does this to + ensure that performance reports represent a fair comparison between rules. + Because there may be no events in this window, and because there may be some + lag before data is available in a performance report, the requested + performance report could contain no to little data. 5. At time `t + 4 hours` another performance report is requested: this time the performance report will contain data from the window between `t + 3 hours` - and `t + 4 hours`, for any authorizations to which both the current version - of the authorization rule (in enforcing mode) and the draft version of the - authorization rule (in shadow mode) applied. + and `t + 4 hours`, for any events to which both the current version of the + Auth rule (in enforcing mode) and the draft version of the Auth rule (in + shadow mode) applied. Note that generating a report may take up to 15 minutes and that delivery is not guaranteed. Customers are required to have created an event subscription to @@ -1593,8 +1652,10 @@ def __init__(self, v2: V2) -> None: self.delete = _legacy_response.to_raw_response_wrapper( v2.delete, ) - self.apply = _legacy_response.to_raw_response_wrapper( - v2.apply, + self.apply = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + v2.apply # pyright: ignore[reportDeprecated], + ) ) self.draft = _legacy_response.to_raw_response_wrapper( v2.draft, @@ -1630,8 +1691,10 @@ def __init__(self, v2: AsyncV2) -> None: self.delete = _legacy_response.async_to_raw_response_wrapper( v2.delete, ) - self.apply = _legacy_response.async_to_raw_response_wrapper( - v2.apply, + self.apply = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + v2.apply # pyright: ignore[reportDeprecated], + ) ) self.draft = _legacy_response.async_to_raw_response_wrapper( v2.draft, @@ -1667,8 +1730,10 @@ def __init__(self, v2: V2) -> None: self.delete = to_streamed_response_wrapper( v2.delete, ) - self.apply = to_streamed_response_wrapper( - v2.apply, + self.apply = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + v2.apply # pyright: ignore[reportDeprecated], + ) ) self.draft = to_streamed_response_wrapper( v2.draft, @@ -1704,8 +1769,10 @@ def __init__(self, v2: AsyncV2) -> None: self.delete = async_to_streamed_response_wrapper( v2.delete, ) - self.apply = async_to_streamed_response_wrapper( - v2.apply, + self.apply = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + v2.apply # pyright: ignore[reportDeprecated], + ) ) self.draft = async_to_streamed_response_wrapper( v2.draft, diff --git a/src/lithic/resources/financial_accounts/financial_accounts.py b/src/lithic/resources/financial_accounts/financial_accounts.py index dccb3df2..4bcbf6f9 100644 --- a/src/lithic/resources/financial_accounts/financial_accounts.py +++ b/src/lithic/resources/financial_accounts/financial_accounts.py @@ -13,8 +13,9 @@ financial_account_create_params, financial_account_update_params, financial_account_update_status_params, + financial_account_register_account_number_params, ) -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven from ..._utils import maybe_transform, async_maybe_transform from .balances import ( Balances, @@ -273,6 +274,46 @@ def list( model=FinancialAccount, ) + def register_account_number( + self, + financial_account_token: str, + *, + account_number: 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: + """ + Register account number + + 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}" + ) + return self._post( + f"/v1/financial_accounts/{financial_account_token}/register_account_number", + body=maybe_transform( + {"account_number": account_number}, + financial_account_register_account_number_params.FinancialAccountRegisterAccountNumberParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + def update_status( self, financial_account_token: str, @@ -531,6 +572,46 @@ def list( model=FinancialAccount, ) + async def register_account_number( + self, + financial_account_token: str, + *, + account_number: 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: + """ + Register account number + + 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}" + ) + return await self._post( + f"/v1/financial_accounts/{financial_account_token}/register_account_number", + body=await async_maybe_transform( + {"account_number": account_number}, + financial_account_register_account_number_params.FinancialAccountRegisterAccountNumberParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + async def update_status( self, financial_account_token: str, @@ -596,6 +677,9 @@ def __init__(self, financial_accounts: FinancialAccounts) -> None: self.list = _legacy_response.to_raw_response_wrapper( financial_accounts.list, ) + self.register_account_number = _legacy_response.to_raw_response_wrapper( + financial_accounts.register_account_number, + ) self.update_status = _legacy_response.to_raw_response_wrapper( financial_accounts.update_status, ) @@ -637,6 +721,9 @@ def __init__(self, financial_accounts: AsyncFinancialAccounts) -> None: self.list = _legacy_response.async_to_raw_response_wrapper( financial_accounts.list, ) + self.register_account_number = _legacy_response.async_to_raw_response_wrapper( + financial_accounts.register_account_number, + ) self.update_status = _legacy_response.async_to_raw_response_wrapper( financial_accounts.update_status, ) @@ -678,6 +765,9 @@ def __init__(self, financial_accounts: FinancialAccounts) -> None: self.list = to_streamed_response_wrapper( financial_accounts.list, ) + self.register_account_number = to_streamed_response_wrapper( + financial_accounts.register_account_number, + ) self.update_status = to_streamed_response_wrapper( financial_accounts.update_status, ) @@ -719,6 +809,9 @@ def __init__(self, financial_accounts: AsyncFinancialAccounts) -> None: self.list = async_to_streamed_response_wrapper( financial_accounts.list, ) + self.register_account_number = async_to_streamed_response_wrapper( + financial_accounts.register_account_number, + ) self.update_status = async_to_streamed_response_wrapper( financial_accounts.update_status, ) diff --git a/src/lithic/resources/three_ds/authentication.py b/src/lithic/resources/three_ds/authentication.py index 66e4af31..81b628cf 100644 --- a/src/lithic/resources/three_ds/authentication.py +++ b/src/lithic/resources/three_ds/authentication.py @@ -93,7 +93,9 @@ def simulate( Simulates a 3DS authentication request from the payment network as if it came from an ACS. If you're configured for 3DS Customer Decisioning, simulating authentications requires your customer decisioning endpoint to be set up - properly (respond with a valid JSON). + properly (respond with a valid JSON). If the authentication decision is to + challenge, ensure that the account holder associated with the card transaction + has a valid phone number configured to receive the OTP code via SMS. Args: pan: Sixteen digit card number. @@ -248,7 +250,9 @@ async def simulate( Simulates a 3DS authentication request from the payment network as if it came from an ACS. If you're configured for 3DS Customer Decisioning, simulating authentications requires your customer decisioning endpoint to be set up - properly (respond with a valid JSON). + properly (respond with a valid JSON). If the authentication decision is to + challenge, ensure that the account holder associated with the card transaction + has a valid phone number configured to receive the OTP code via SMS. Args: pan: Sixteen digit card number. diff --git a/src/lithic/types/__init__.py b/src/lithic/types/__init__.py index 250e25de..b2d297d2 100644 --- a/src/lithic/types/__init__.py +++ b/src/lithic/types/__init__.py @@ -195,6 +195,9 @@ from .account_holder_simulate_enrollment_review_params import ( AccountHolderSimulateEnrollmentReviewParams as AccountHolderSimulateEnrollmentReviewParams, ) +from .financial_account_register_account_number_params import ( + FinancialAccountRegisterAccountNumberParams as FinancialAccountRegisterAccountNumberParams, +) from .transaction_simulate_authorization_advice_params import ( TransactionSimulateAuthorizationAdviceParams as TransactionSimulateAuthorizationAdviceParams, ) diff --git a/src/lithic/types/account.py b/src/lithic/types/account.py index cc78097c..4b8a48c4 100644 --- a/src/lithic/types/account.py +++ b/src/lithic/types/account.py @@ -94,11 +94,11 @@ class Account(BaseModel): - `PAUSED` - Account will not be able to transact or create new cards. It can be set back to `ACTIVE`. - `CLOSED` - Account will not be able to transact or create new cards. `CLOSED` - accounts are also unable to be transitioned to `ACTIVE` or `PAUSED` states. - `CLOSED` accounts result from failing to pass KYB/KYC or Lithic closing for - risk/compliance reasons. Please contact - [support@lithic.com](mailto:support@lithic.com) if you believe this was in - error. + accounts are unable to be transitioned to `ACTIVE` or `PAUSED` states. + Accounts can be manually set to `CLOSED`, or this can be done by Lithic due to + failure to pass KYB/KYC or for risk/compliance reasons. Please contact + [support@lithic.com](mailto:support@lithic.com) if you believe this was done + by mistake. """ account_holder: Optional[AccountHolder] = None diff --git a/src/lithic/types/account_update_params.py b/src/lithic/types/account_update_params.py index ed9e95f8..bef88c66 100644 --- a/src/lithic/types/account_update_params.py +++ b/src/lithic/types/account_update_params.py @@ -33,15 +33,15 @@ class AccountUpdateParams(TypedDict, total=False): $5,000. """ - state: Literal["ACTIVE", "PAUSED"] + state: Literal["ACTIVE", "PAUSED", "CLOSED"] """Account states.""" verification_address: VerificationAddress """ Address used during Address Verification Service (AVS) checks during transactions if enabled via Auth Rules. This field is deprecated as AVS checks - are no longer supported by Authorization Rules. The field will be removed from - the schema in a future release. + are no longer supported by Auth Rules. The field will be removed from the schema + in a future release. """ diff --git a/src/lithic/types/auth_rules/v2/backtest_results.py b/src/lithic/types/auth_rules/v2/backtest_results.py index 20f6916a..7d5e223f 100644 --- a/src/lithic/types/auth_rules/v2/backtest_results.py +++ b/src/lithic/types/auth_rules/v2/backtest_results.py @@ -2,6 +2,7 @@ from typing import List, Optional from datetime import datetime +from typing_extensions import Literal from ...._models import BaseModel @@ -18,32 +19,43 @@ class ResultsCurrentVersionExample(BaseModel): approved: Optional[bool] = None - """Whether the rule would have approved the authorization request.""" + """Whether the rule would have approved the request.""" + + decision: Optional[Literal["APPROVED", "DECLINED", "CHALLENGED"]] = None + """The decision made by the rule for this event.""" event_token: Optional[str] = None - """The authorization request event token.""" + """The event token.""" timestamp: Optional[datetime] = None - """The timestamp of the authorization request event.""" + """The timestamp of the event.""" class ResultsCurrentVersion(BaseModel): approved: Optional[int] = None """ The total number of historical transactions approved by this rule during the - backtest period, or the number of transactions that would have been approved if + relevant period, or the number of transactions that would have been approved if the rule was evaluated in shadow mode. """ + challenged: Optional[int] = None + """ + The total number of historical transactions challenged by this rule during the + relevant period, or the number of transactions that would have been challenged + if the rule was evaluated in shadow mode. Currently applicable only for 3DS Auth + Rules. + """ + declined: Optional[int] = None """ The total number of historical transactions declined by this rule during the - backtest period, or the number of transactions that would have been declined if + relevant period, or the number of transactions that would have been declined if the rule was evaluated in shadow mode. """ examples: Optional[List[ResultsCurrentVersionExample]] = None - """Example authorization request events that would have been approved or declined.""" + """Example events and their outcomes.""" version: Optional[int] = None """ @@ -54,32 +66,43 @@ class ResultsCurrentVersion(BaseModel): class ResultsDraftVersionExample(BaseModel): approved: Optional[bool] = None - """Whether the rule would have approved the authorization request.""" + """Whether the rule would have approved the request.""" + + decision: Optional[Literal["APPROVED", "DECLINED", "CHALLENGED"]] = None + """The decision made by the rule for this event.""" event_token: Optional[str] = None - """The authorization request event token.""" + """The event token.""" timestamp: Optional[datetime] = None - """The timestamp of the authorization request event.""" + """The timestamp of the event.""" class ResultsDraftVersion(BaseModel): approved: Optional[int] = None """ The total number of historical transactions approved by this rule during the - backtest period, or the number of transactions that would have been approved if + relevant period, or the number of transactions that would have been approved if the rule was evaluated in shadow mode. """ + challenged: Optional[int] = None + """ + The total number of historical transactions challenged by this rule during the + relevant period, or the number of transactions that would have been challenged + if the rule was evaluated in shadow mode. Currently applicable only for 3DS Auth + Rules. + """ + declined: Optional[int] = None """ The total number of historical transactions declined by this rule during the - backtest period, or the number of transactions that would have been declined if + relevant period, or the number of transactions that would have been declined if the rule was evaluated in shadow mode. """ examples: Optional[List[ResultsDraftVersionExample]] = None - """Example authorization request events that would have been approved or declined.""" + """Example events and their outcomes.""" version: Optional[int] = None """ diff --git a/src/lithic/types/auth_rules/v2_apply_response.py b/src/lithic/types/auth_rules/v2_apply_response.py index d18dcdb6..3836bdda 100644 --- a/src/lithic/types/auth_rules/v2_apply_response.py +++ b/src/lithic/types/auth_rules/v2_apply_response.py @@ -13,10 +13,14 @@ "CurrentVersionParameters", "CurrentVersionParametersMerchantLockParameters", "CurrentVersionParametersMerchantLockParametersMerchant", + "CurrentVersionParametersConditional3DSActionParameters", + "CurrentVersionParametersConditional3DsActionParametersCondition", "DraftVersion", "DraftVersionParameters", "DraftVersionParametersMerchantLockParameters", "DraftVersionParametersMerchantLockParametersMerchant", + "DraftVersionParametersConditional3DSActionParameters", + "DraftVersionParametersConditional3DsActionParametersCondition", ] @@ -50,8 +54,66 @@ class CurrentVersionParametersMerchantLockParameters(BaseModel): """ +class CurrentVersionParametersConditional3DsActionParametersCondition(BaseModel): + attribute: Optional[ + Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + ] = None + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Optional[ + Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + ] = None + """The operation to apply to the attribute""" + + value: Union[str, int, List[str], None] = None + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class CurrentVersionParametersConditional3DSActionParameters(BaseModel): + action: Literal["DECLINE", "CHALLENGE"] + """The action to take if the conditions are met.""" + + conditions: List[CurrentVersionParametersConditional3DsActionParametersCondition] + + CurrentVersionParameters: TypeAlias = Union[ - ConditionalBlockParameters, VelocityLimitParams, CurrentVersionParametersMerchantLockParameters + ConditionalBlockParameters, + VelocityLimitParams, + CurrentVersionParametersMerchantLockParameters, + CurrentVersionParametersConditional3DSActionParameters, ] @@ -96,8 +158,66 @@ class DraftVersionParametersMerchantLockParameters(BaseModel): """ +class DraftVersionParametersConditional3DsActionParametersCondition(BaseModel): + attribute: Optional[ + Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + ] = None + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Optional[ + Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + ] = None + """The operation to apply to the attribute""" + + value: Union[str, int, List[str], None] = None + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class DraftVersionParametersConditional3DSActionParameters(BaseModel): + action: Literal["DECLINE", "CHALLENGE"] + """The action to take if the conditions are met.""" + + conditions: List[DraftVersionParametersConditional3DsActionParametersCondition] + + DraftVersionParameters: TypeAlias = Union[ - ConditionalBlockParameters, VelocityLimitParams, DraftVersionParametersMerchantLockParameters + ConditionalBlockParameters, + VelocityLimitParams, + DraftVersionParametersMerchantLockParameters, + DraftVersionParametersConditional3DSActionParameters, ] @@ -126,6 +246,9 @@ class V2ApplyResponse(BaseModel): draft_version: Optional[DraftVersion] = None + event_stream: Literal["AUTHORIZATION", "THREE_DS_AUTHENTICATION"] + """The type of event stream the Auth rule applies to.""" + name: Optional[str] = None """Auth Rule Name""" @@ -135,8 +258,16 @@ class V2ApplyResponse(BaseModel): state: Literal["ACTIVE", "INACTIVE"] """The state of the Auth Rule""" - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] - """The type of Auth Rule""" + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + """The type of Auth Rule. + + Effectively determines the event stream during which it will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. + """ excluded_card_tokens: Optional[List[str]] = None """Card tokens to which the Auth Rule does not apply.""" diff --git a/src/lithic/types/auth_rules/v2_create_params.py b/src/lithic/types/auth_rules/v2_create_params.py index 42ee2ff8..62136bf6 100644 --- a/src/lithic/types/auth_rules/v2_create_params.py +++ b/src/lithic/types/auth_rules/v2_create_params.py @@ -14,14 +14,20 @@ "CreateAuthRuleRequestAccountTokensParameters", "CreateAuthRuleRequestAccountTokensParametersMerchantLockParameters", "CreateAuthRuleRequestAccountTokensParametersMerchantLockParametersMerchant", + "CreateAuthRuleRequestAccountTokensParametersConditional3DSActionParameters", + "CreateAuthRuleRequestAccountTokensParametersConditional3DsActionParametersCondition", "CreateAuthRuleRequestCardTokens", "CreateAuthRuleRequestCardTokensParameters", "CreateAuthRuleRequestCardTokensParametersMerchantLockParameters", "CreateAuthRuleRequestCardTokensParametersMerchantLockParametersMerchant", + "CreateAuthRuleRequestCardTokensParametersConditional3DSActionParameters", + "CreateAuthRuleRequestCardTokensParametersConditional3DsActionParametersCondition", "CreateAuthRuleRequestProgramLevel", "CreateAuthRuleRequestProgramLevelParameters", "CreateAuthRuleRequestProgramLevelParametersMerchantLockParameters", "CreateAuthRuleRequestProgramLevelParametersMerchantLockParametersMerchant", + "CreateAuthRuleRequestProgramLevelParametersConditional3DSActionParameters", + "CreateAuthRuleRequestProgramLevelParametersConditional3DsActionParametersCondition", ] @@ -35,8 +41,16 @@ class CreateAuthRuleRequestAccountTokens(TypedDict, total=False): parameters: CreateAuthRuleRequestAccountTokensParameters """Parameters for the Auth Rule""" - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] - """The type of Auth Rule""" + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + """The type of Auth Rule. + + Effectively determines the event stream during which it will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. + """ class CreateAuthRuleRequestAccountTokensParametersMerchantLockParametersMerchant(TypedDict, total=False): @@ -69,10 +83,62 @@ class CreateAuthRuleRequestAccountTokensParametersMerchantLockParameters(TypedDi """ +class CreateAuthRuleRequestAccountTokensParametersConditional3DsActionParametersCondition(TypedDict, total=False): + attribute: Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + """The operation to apply to the attribute""" + + value: Union[str, int, List[str]] + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class CreateAuthRuleRequestAccountTokensParametersConditional3DSActionParameters(TypedDict, total=False): + action: Required[Literal["DECLINE", "CHALLENGE"]] + """The action to take if the conditions are met.""" + + conditions: Required[Iterable[CreateAuthRuleRequestAccountTokensParametersConditional3DsActionParametersCondition]] + + CreateAuthRuleRequestAccountTokensParameters: TypeAlias = Union[ ConditionalBlockParametersParam, VelocityLimitParamsParam, CreateAuthRuleRequestAccountTokensParametersMerchantLockParameters, + CreateAuthRuleRequestAccountTokensParametersConditional3DSActionParameters, ] @@ -86,8 +152,16 @@ class CreateAuthRuleRequestCardTokens(TypedDict, total=False): parameters: CreateAuthRuleRequestCardTokensParameters """Parameters for the Auth Rule""" - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] - """The type of Auth Rule""" + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + """The type of Auth Rule. + + Effectively determines the event stream during which it will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. + """ class CreateAuthRuleRequestCardTokensParametersMerchantLockParametersMerchant(TypedDict, total=False): @@ -120,10 +194,62 @@ class CreateAuthRuleRequestCardTokensParametersMerchantLockParameters(TypedDict, """ +class CreateAuthRuleRequestCardTokensParametersConditional3DsActionParametersCondition(TypedDict, total=False): + attribute: Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + """The operation to apply to the attribute""" + + value: Union[str, int, List[str]] + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class CreateAuthRuleRequestCardTokensParametersConditional3DSActionParameters(TypedDict, total=False): + action: Required[Literal["DECLINE", "CHALLENGE"]] + """The action to take if the conditions are met.""" + + conditions: Required[Iterable[CreateAuthRuleRequestCardTokensParametersConditional3DsActionParametersCondition]] + + CreateAuthRuleRequestCardTokensParameters: TypeAlias = Union[ ConditionalBlockParametersParam, VelocityLimitParamsParam, CreateAuthRuleRequestCardTokensParametersMerchantLockParameters, + CreateAuthRuleRequestCardTokensParametersConditional3DSActionParameters, ] @@ -140,8 +266,16 @@ class CreateAuthRuleRequestProgramLevel(TypedDict, total=False): parameters: CreateAuthRuleRequestProgramLevelParameters """Parameters for the Auth Rule""" - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] - """The type of Auth Rule""" + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + """The type of Auth Rule. + + Effectively determines the event stream during which it will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. + """ class CreateAuthRuleRequestProgramLevelParametersMerchantLockParametersMerchant(TypedDict, total=False): @@ -174,10 +308,62 @@ class CreateAuthRuleRequestProgramLevelParametersMerchantLockParameters(TypedDic """ +class CreateAuthRuleRequestProgramLevelParametersConditional3DsActionParametersCondition(TypedDict, total=False): + attribute: Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + """The operation to apply to the attribute""" + + value: Union[str, int, List[str]] + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class CreateAuthRuleRequestProgramLevelParametersConditional3DSActionParameters(TypedDict, total=False): + action: Required[Literal["DECLINE", "CHALLENGE"]] + """The action to take if the conditions are met.""" + + conditions: Required[Iterable[CreateAuthRuleRequestProgramLevelParametersConditional3DsActionParametersCondition]] + + CreateAuthRuleRequestProgramLevelParameters: TypeAlias = Union[ ConditionalBlockParametersParam, VelocityLimitParamsParam, CreateAuthRuleRequestProgramLevelParametersMerchantLockParameters, + CreateAuthRuleRequestProgramLevelParametersConditional3DSActionParameters, ] V2CreateParams: TypeAlias = Union[ diff --git a/src/lithic/types/auth_rules/v2_create_response.py b/src/lithic/types/auth_rules/v2_create_response.py index 05686de1..ba34fa56 100644 --- a/src/lithic/types/auth_rules/v2_create_response.py +++ b/src/lithic/types/auth_rules/v2_create_response.py @@ -13,10 +13,14 @@ "CurrentVersionParameters", "CurrentVersionParametersMerchantLockParameters", "CurrentVersionParametersMerchantLockParametersMerchant", + "CurrentVersionParametersConditional3DSActionParameters", + "CurrentVersionParametersConditional3DsActionParametersCondition", "DraftVersion", "DraftVersionParameters", "DraftVersionParametersMerchantLockParameters", "DraftVersionParametersMerchantLockParametersMerchant", + "DraftVersionParametersConditional3DSActionParameters", + "DraftVersionParametersConditional3DsActionParametersCondition", ] @@ -50,8 +54,66 @@ class CurrentVersionParametersMerchantLockParameters(BaseModel): """ +class CurrentVersionParametersConditional3DsActionParametersCondition(BaseModel): + attribute: Optional[ + Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + ] = None + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Optional[ + Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + ] = None + """The operation to apply to the attribute""" + + value: Union[str, int, List[str], None] = None + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class CurrentVersionParametersConditional3DSActionParameters(BaseModel): + action: Literal["DECLINE", "CHALLENGE"] + """The action to take if the conditions are met.""" + + conditions: List[CurrentVersionParametersConditional3DsActionParametersCondition] + + CurrentVersionParameters: TypeAlias = Union[ - ConditionalBlockParameters, VelocityLimitParams, CurrentVersionParametersMerchantLockParameters + ConditionalBlockParameters, + VelocityLimitParams, + CurrentVersionParametersMerchantLockParameters, + CurrentVersionParametersConditional3DSActionParameters, ] @@ -96,8 +158,66 @@ class DraftVersionParametersMerchantLockParameters(BaseModel): """ +class DraftVersionParametersConditional3DsActionParametersCondition(BaseModel): + attribute: Optional[ + Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + ] = None + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Optional[ + Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + ] = None + """The operation to apply to the attribute""" + + value: Union[str, int, List[str], None] = None + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class DraftVersionParametersConditional3DSActionParameters(BaseModel): + action: Literal["DECLINE", "CHALLENGE"] + """The action to take if the conditions are met.""" + + conditions: List[DraftVersionParametersConditional3DsActionParametersCondition] + + DraftVersionParameters: TypeAlias = Union[ - ConditionalBlockParameters, VelocityLimitParams, DraftVersionParametersMerchantLockParameters + ConditionalBlockParameters, + VelocityLimitParams, + DraftVersionParametersMerchantLockParameters, + DraftVersionParametersConditional3DSActionParameters, ] @@ -126,6 +246,9 @@ class V2CreateResponse(BaseModel): draft_version: Optional[DraftVersion] = None + event_stream: Literal["AUTHORIZATION", "THREE_DS_AUTHENTICATION"] + """The type of event stream the Auth rule applies to.""" + name: Optional[str] = None """Auth Rule Name""" @@ -135,8 +258,16 @@ class V2CreateResponse(BaseModel): state: Literal["ACTIVE", "INACTIVE"] """The state of the Auth Rule""" - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] - """The type of Auth Rule""" + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + """The type of Auth Rule. + + Effectively determines the event stream during which it will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. + """ excluded_card_tokens: Optional[List[str]] = None """Card tokens to which the Auth Rule does not apply.""" diff --git a/src/lithic/types/auth_rules/v2_draft_params.py b/src/lithic/types/auth_rules/v2_draft_params.py index e90da23a..b76efb4c 100644 --- a/src/lithic/types/auth_rules/v2_draft_params.py +++ b/src/lithic/types/auth_rules/v2_draft_params.py @@ -2,8 +2,8 @@ from __future__ import annotations -from typing import Union, Iterable, Optional -from typing_extensions import Required, TypeAlias, TypedDict +from typing import List, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict from .velocity_limit_params_param import VelocityLimitParamsParam from .conditional_block_parameters_param import ConditionalBlockParametersParam @@ -13,6 +13,8 @@ "Parameters", "ParametersMerchantLockParameters", "ParametersMerchantLockParametersMerchant", + "ParametersConditional3DSActionParameters", + "ParametersConditional3DsActionParametersCondition", ] @@ -51,6 +53,60 @@ class ParametersMerchantLockParameters(TypedDict, total=False): """ +class ParametersConditional3DsActionParametersCondition(TypedDict, total=False): + attribute: Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + """The operation to apply to the attribute""" + + value: Union[str, int, List[str]] + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class ParametersConditional3DSActionParameters(TypedDict, total=False): + action: Required[Literal["DECLINE", "CHALLENGE"]] + """The action to take if the conditions are met.""" + + conditions: Required[Iterable[ParametersConditional3DsActionParametersCondition]] + + Parameters: TypeAlias = Union[ - ConditionalBlockParametersParam, VelocityLimitParamsParam, ParametersMerchantLockParameters + ConditionalBlockParametersParam, + VelocityLimitParamsParam, + ParametersMerchantLockParameters, + ParametersConditional3DSActionParameters, ] diff --git a/src/lithic/types/auth_rules/v2_draft_response.py b/src/lithic/types/auth_rules/v2_draft_response.py index d2b830bb..870bed39 100644 --- a/src/lithic/types/auth_rules/v2_draft_response.py +++ b/src/lithic/types/auth_rules/v2_draft_response.py @@ -13,10 +13,14 @@ "CurrentVersionParameters", "CurrentVersionParametersMerchantLockParameters", "CurrentVersionParametersMerchantLockParametersMerchant", + "CurrentVersionParametersConditional3DSActionParameters", + "CurrentVersionParametersConditional3DsActionParametersCondition", "DraftVersion", "DraftVersionParameters", "DraftVersionParametersMerchantLockParameters", "DraftVersionParametersMerchantLockParametersMerchant", + "DraftVersionParametersConditional3DSActionParameters", + "DraftVersionParametersConditional3DsActionParametersCondition", ] @@ -50,8 +54,66 @@ class CurrentVersionParametersMerchantLockParameters(BaseModel): """ +class CurrentVersionParametersConditional3DsActionParametersCondition(BaseModel): + attribute: Optional[ + Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + ] = None + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Optional[ + Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + ] = None + """The operation to apply to the attribute""" + + value: Union[str, int, List[str], None] = None + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class CurrentVersionParametersConditional3DSActionParameters(BaseModel): + action: Literal["DECLINE", "CHALLENGE"] + """The action to take if the conditions are met.""" + + conditions: List[CurrentVersionParametersConditional3DsActionParametersCondition] + + CurrentVersionParameters: TypeAlias = Union[ - ConditionalBlockParameters, VelocityLimitParams, CurrentVersionParametersMerchantLockParameters + ConditionalBlockParameters, + VelocityLimitParams, + CurrentVersionParametersMerchantLockParameters, + CurrentVersionParametersConditional3DSActionParameters, ] @@ -96,8 +158,66 @@ class DraftVersionParametersMerchantLockParameters(BaseModel): """ +class DraftVersionParametersConditional3DsActionParametersCondition(BaseModel): + attribute: Optional[ + Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + ] = None + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Optional[ + Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + ] = None + """The operation to apply to the attribute""" + + value: Union[str, int, List[str], None] = None + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class DraftVersionParametersConditional3DSActionParameters(BaseModel): + action: Literal["DECLINE", "CHALLENGE"] + """The action to take if the conditions are met.""" + + conditions: List[DraftVersionParametersConditional3DsActionParametersCondition] + + DraftVersionParameters: TypeAlias = Union[ - ConditionalBlockParameters, VelocityLimitParams, DraftVersionParametersMerchantLockParameters + ConditionalBlockParameters, + VelocityLimitParams, + DraftVersionParametersMerchantLockParameters, + DraftVersionParametersConditional3DSActionParameters, ] @@ -126,6 +246,9 @@ class V2DraftResponse(BaseModel): draft_version: Optional[DraftVersion] = None + event_stream: Literal["AUTHORIZATION", "THREE_DS_AUTHENTICATION"] + """The type of event stream the Auth rule applies to.""" + name: Optional[str] = None """Auth Rule Name""" @@ -135,8 +258,16 @@ class V2DraftResponse(BaseModel): state: Literal["ACTIVE", "INACTIVE"] """The state of the Auth Rule""" - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] - """The type of Auth Rule""" + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + """The type of Auth Rule. + + Effectively determines the event stream during which it will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. + """ excluded_card_tokens: Optional[List[str]] = None """Card tokens to which the Auth Rule does not apply.""" diff --git a/src/lithic/types/auth_rules/v2_list_params.py b/src/lithic/types/auth_rules/v2_list_params.py index daeca3ce..4b908752 100644 --- a/src/lithic/types/auth_rules/v2_list_params.py +++ b/src/lithic/types/auth_rules/v2_list_params.py @@ -9,10 +9,10 @@ class V2ListParams(TypedDict, total=False): account_token: str - """Only return Authorization Rules that are bound to the provided account token.""" + """Only return Auth Rules that are bound to the provided account token.""" card_token: str - """Only return Authorization Rules that are bound to the provided card token.""" + """Only return Auth Rules that are bound to the provided card token.""" ending_before: str """A cursor representing an item's token before which a page of results should end. @@ -20,11 +20,14 @@ class V2ListParams(TypedDict, total=False): Used to retrieve the previous page of results before this item. """ + event_stream: Literal["AUTHORIZATION", "THREE_DS_AUTHENTICATION"] + """Only return Auth rules that are executed during the provided event stream.""" + page_size: int """Page size (for pagination).""" scope: Literal["PROGRAM", "ACCOUNT", "CARD"] - """Only return Authorization Rules that are bound to the provided scope;""" + """Only return Auth Rules that are bound to the provided scope.""" starting_after: str """A cursor representing an item's token after which a page of results should diff --git a/src/lithic/types/auth_rules/v2_list_response.py b/src/lithic/types/auth_rules/v2_list_response.py index a53ab7c7..182dc3f1 100644 --- a/src/lithic/types/auth_rules/v2_list_response.py +++ b/src/lithic/types/auth_rules/v2_list_response.py @@ -13,10 +13,14 @@ "CurrentVersionParameters", "CurrentVersionParametersMerchantLockParameters", "CurrentVersionParametersMerchantLockParametersMerchant", + "CurrentVersionParametersConditional3DSActionParameters", + "CurrentVersionParametersConditional3DsActionParametersCondition", "DraftVersion", "DraftVersionParameters", "DraftVersionParametersMerchantLockParameters", "DraftVersionParametersMerchantLockParametersMerchant", + "DraftVersionParametersConditional3DSActionParameters", + "DraftVersionParametersConditional3DsActionParametersCondition", ] @@ -50,8 +54,66 @@ class CurrentVersionParametersMerchantLockParameters(BaseModel): """ +class CurrentVersionParametersConditional3DsActionParametersCondition(BaseModel): + attribute: Optional[ + Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + ] = None + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Optional[ + Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + ] = None + """The operation to apply to the attribute""" + + value: Union[str, int, List[str], None] = None + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class CurrentVersionParametersConditional3DSActionParameters(BaseModel): + action: Literal["DECLINE", "CHALLENGE"] + """The action to take if the conditions are met.""" + + conditions: List[CurrentVersionParametersConditional3DsActionParametersCondition] + + CurrentVersionParameters: TypeAlias = Union[ - ConditionalBlockParameters, VelocityLimitParams, CurrentVersionParametersMerchantLockParameters + ConditionalBlockParameters, + VelocityLimitParams, + CurrentVersionParametersMerchantLockParameters, + CurrentVersionParametersConditional3DSActionParameters, ] @@ -96,8 +158,66 @@ class DraftVersionParametersMerchantLockParameters(BaseModel): """ +class DraftVersionParametersConditional3DsActionParametersCondition(BaseModel): + attribute: Optional[ + Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + ] = None + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Optional[ + Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + ] = None + """The operation to apply to the attribute""" + + value: Union[str, int, List[str], None] = None + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class DraftVersionParametersConditional3DSActionParameters(BaseModel): + action: Literal["DECLINE", "CHALLENGE"] + """The action to take if the conditions are met.""" + + conditions: List[DraftVersionParametersConditional3DsActionParametersCondition] + + DraftVersionParameters: TypeAlias = Union[ - ConditionalBlockParameters, VelocityLimitParams, DraftVersionParametersMerchantLockParameters + ConditionalBlockParameters, + VelocityLimitParams, + DraftVersionParametersMerchantLockParameters, + DraftVersionParametersConditional3DSActionParameters, ] @@ -126,6 +246,9 @@ class V2ListResponse(BaseModel): draft_version: Optional[DraftVersion] = None + event_stream: Literal["AUTHORIZATION", "THREE_DS_AUTHENTICATION"] + """The type of event stream the Auth rule applies to.""" + name: Optional[str] = None """Auth Rule Name""" @@ -135,8 +258,16 @@ class V2ListResponse(BaseModel): state: Literal["ACTIVE", "INACTIVE"] """The state of the Auth Rule""" - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] - """The type of Auth Rule""" + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + """The type of Auth Rule. + + Effectively determines the event stream during which it will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. + """ excluded_card_tokens: Optional[List[str]] = None """Card tokens to which the Auth Rule does not apply.""" diff --git a/src/lithic/types/auth_rules/v2_promote_response.py b/src/lithic/types/auth_rules/v2_promote_response.py index 0d26f143..590561b4 100644 --- a/src/lithic/types/auth_rules/v2_promote_response.py +++ b/src/lithic/types/auth_rules/v2_promote_response.py @@ -13,10 +13,14 @@ "CurrentVersionParameters", "CurrentVersionParametersMerchantLockParameters", "CurrentVersionParametersMerchantLockParametersMerchant", + "CurrentVersionParametersConditional3DSActionParameters", + "CurrentVersionParametersConditional3DsActionParametersCondition", "DraftVersion", "DraftVersionParameters", "DraftVersionParametersMerchantLockParameters", "DraftVersionParametersMerchantLockParametersMerchant", + "DraftVersionParametersConditional3DSActionParameters", + "DraftVersionParametersConditional3DsActionParametersCondition", ] @@ -50,8 +54,66 @@ class CurrentVersionParametersMerchantLockParameters(BaseModel): """ +class CurrentVersionParametersConditional3DsActionParametersCondition(BaseModel): + attribute: Optional[ + Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + ] = None + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Optional[ + Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + ] = None + """The operation to apply to the attribute""" + + value: Union[str, int, List[str], None] = None + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class CurrentVersionParametersConditional3DSActionParameters(BaseModel): + action: Literal["DECLINE", "CHALLENGE"] + """The action to take if the conditions are met.""" + + conditions: List[CurrentVersionParametersConditional3DsActionParametersCondition] + + CurrentVersionParameters: TypeAlias = Union[ - ConditionalBlockParameters, VelocityLimitParams, CurrentVersionParametersMerchantLockParameters + ConditionalBlockParameters, + VelocityLimitParams, + CurrentVersionParametersMerchantLockParameters, + CurrentVersionParametersConditional3DSActionParameters, ] @@ -96,8 +158,66 @@ class DraftVersionParametersMerchantLockParameters(BaseModel): """ +class DraftVersionParametersConditional3DsActionParametersCondition(BaseModel): + attribute: Optional[ + Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + ] = None + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Optional[ + Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + ] = None + """The operation to apply to the attribute""" + + value: Union[str, int, List[str], None] = None + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class DraftVersionParametersConditional3DSActionParameters(BaseModel): + action: Literal["DECLINE", "CHALLENGE"] + """The action to take if the conditions are met.""" + + conditions: List[DraftVersionParametersConditional3DsActionParametersCondition] + + DraftVersionParameters: TypeAlias = Union[ - ConditionalBlockParameters, VelocityLimitParams, DraftVersionParametersMerchantLockParameters + ConditionalBlockParameters, + VelocityLimitParams, + DraftVersionParametersMerchantLockParameters, + DraftVersionParametersConditional3DSActionParameters, ] @@ -126,6 +246,9 @@ class V2PromoteResponse(BaseModel): draft_version: Optional[DraftVersion] = None + event_stream: Literal["AUTHORIZATION", "THREE_DS_AUTHENTICATION"] + """The type of event stream the Auth rule applies to.""" + name: Optional[str] = None """Auth Rule Name""" @@ -135,8 +258,16 @@ class V2PromoteResponse(BaseModel): state: Literal["ACTIVE", "INACTIVE"] """The state of the Auth Rule""" - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] - """The type of Auth Rule""" + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + """The type of Auth Rule. + + Effectively determines the event stream during which it will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. + """ excluded_card_tokens: Optional[List[str]] = None """Card tokens to which the Auth Rule does not apply.""" diff --git a/src/lithic/types/auth_rules/v2_retrieve_response.py b/src/lithic/types/auth_rules/v2_retrieve_response.py index 9b9ce7f1..367602ab 100644 --- a/src/lithic/types/auth_rules/v2_retrieve_response.py +++ b/src/lithic/types/auth_rules/v2_retrieve_response.py @@ -13,10 +13,14 @@ "CurrentVersionParameters", "CurrentVersionParametersMerchantLockParameters", "CurrentVersionParametersMerchantLockParametersMerchant", + "CurrentVersionParametersConditional3DSActionParameters", + "CurrentVersionParametersConditional3DsActionParametersCondition", "DraftVersion", "DraftVersionParameters", "DraftVersionParametersMerchantLockParameters", "DraftVersionParametersMerchantLockParametersMerchant", + "DraftVersionParametersConditional3DSActionParameters", + "DraftVersionParametersConditional3DsActionParametersCondition", ] @@ -50,8 +54,66 @@ class CurrentVersionParametersMerchantLockParameters(BaseModel): """ +class CurrentVersionParametersConditional3DsActionParametersCondition(BaseModel): + attribute: Optional[ + Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + ] = None + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Optional[ + Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + ] = None + """The operation to apply to the attribute""" + + value: Union[str, int, List[str], None] = None + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class CurrentVersionParametersConditional3DSActionParameters(BaseModel): + action: Literal["DECLINE", "CHALLENGE"] + """The action to take if the conditions are met.""" + + conditions: List[CurrentVersionParametersConditional3DsActionParametersCondition] + + CurrentVersionParameters: TypeAlias = Union[ - ConditionalBlockParameters, VelocityLimitParams, CurrentVersionParametersMerchantLockParameters + ConditionalBlockParameters, + VelocityLimitParams, + CurrentVersionParametersMerchantLockParameters, + CurrentVersionParametersConditional3DSActionParameters, ] @@ -96,8 +158,66 @@ class DraftVersionParametersMerchantLockParameters(BaseModel): """ +class DraftVersionParametersConditional3DsActionParametersCondition(BaseModel): + attribute: Optional[ + Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + ] = None + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Optional[ + Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + ] = None + """The operation to apply to the attribute""" + + value: Union[str, int, List[str], None] = None + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class DraftVersionParametersConditional3DSActionParameters(BaseModel): + action: Literal["DECLINE", "CHALLENGE"] + """The action to take if the conditions are met.""" + + conditions: List[DraftVersionParametersConditional3DsActionParametersCondition] + + DraftVersionParameters: TypeAlias = Union[ - ConditionalBlockParameters, VelocityLimitParams, DraftVersionParametersMerchantLockParameters + ConditionalBlockParameters, + VelocityLimitParams, + DraftVersionParametersMerchantLockParameters, + DraftVersionParametersConditional3DSActionParameters, ] @@ -126,6 +246,9 @@ class V2RetrieveResponse(BaseModel): draft_version: Optional[DraftVersion] = None + event_stream: Literal["AUTHORIZATION", "THREE_DS_AUTHENTICATION"] + """The type of event stream the Auth rule applies to.""" + name: Optional[str] = None """Auth Rule Name""" @@ -135,8 +258,16 @@ class V2RetrieveResponse(BaseModel): state: Literal["ACTIVE", "INACTIVE"] """The state of the Auth Rule""" - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] - """The type of Auth Rule""" + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + """The type of Auth Rule. + + Effectively determines the event stream during which it will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. + """ excluded_card_tokens: Optional[List[str]] = None """Card tokens to which the Auth Rule does not apply.""" diff --git a/src/lithic/types/auth_rules/v2_update_response.py b/src/lithic/types/auth_rules/v2_update_response.py index 681846ec..97b2f875 100644 --- a/src/lithic/types/auth_rules/v2_update_response.py +++ b/src/lithic/types/auth_rules/v2_update_response.py @@ -13,10 +13,14 @@ "CurrentVersionParameters", "CurrentVersionParametersMerchantLockParameters", "CurrentVersionParametersMerchantLockParametersMerchant", + "CurrentVersionParametersConditional3DSActionParameters", + "CurrentVersionParametersConditional3DsActionParametersCondition", "DraftVersion", "DraftVersionParameters", "DraftVersionParametersMerchantLockParameters", "DraftVersionParametersMerchantLockParametersMerchant", + "DraftVersionParametersConditional3DSActionParameters", + "DraftVersionParametersConditional3DsActionParametersCondition", ] @@ -50,8 +54,66 @@ class CurrentVersionParametersMerchantLockParameters(BaseModel): """ +class CurrentVersionParametersConditional3DsActionParametersCondition(BaseModel): + attribute: Optional[ + Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + ] = None + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Optional[ + Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + ] = None + """The operation to apply to the attribute""" + + value: Union[str, int, List[str], None] = None + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class CurrentVersionParametersConditional3DSActionParameters(BaseModel): + action: Literal["DECLINE", "CHALLENGE"] + """The action to take if the conditions are met.""" + + conditions: List[CurrentVersionParametersConditional3DsActionParametersCondition] + + CurrentVersionParameters: TypeAlias = Union[ - ConditionalBlockParameters, VelocityLimitParams, CurrentVersionParametersMerchantLockParameters + ConditionalBlockParameters, + VelocityLimitParams, + CurrentVersionParametersMerchantLockParameters, + CurrentVersionParametersConditional3DSActionParameters, ] @@ -96,8 +158,66 @@ class DraftVersionParametersMerchantLockParameters(BaseModel): """ +class DraftVersionParametersConditional3DsActionParametersCondition(BaseModel): + attribute: Optional[ + Literal[ + "MCC", + "COUNTRY", + "CURRENCY", + "MERCHANT_ID", + "DESCRIPTOR", + "TRANSACTION_AMOUNT", + "RISK_SCORE", + "MESSAGE_CATEGORY", + ] + ] = None + """The attribute to target. + + The following attributes may be targeted: + + - `MCC`: A four-digit number listed in ISO 18245. An MCC is used to classify a + business by the types of goods or services it provides. + - `COUNTRY`: Country of entity of card acceptor. Possible values are: (1) all + ISO 3166-1 alpha-3 country codes, (2) QZZ for Kosovo, and (3) ANT for + Netherlands Antilles. + - `CURRENCY`: 3-character alphabetic ISO 4217 code for the merchant currency of + the transaction. + - `MERCHANT_ID`: Unique alphanumeric identifier for the payment card acceptor + (merchant). + - `DESCRIPTOR`: Short description of card acceptor. + - `TRANSACTION_AMOUNT`: The base transaction amount (in cents) plus the acquirer + fee field in the settlement/cardholder billing currency. This is the amount + the issuer should authorize against unless the issuer is paying the acquirer + fee on behalf of the cardholder. + - `RISK_SCORE`: Network-provided score assessing risk level associated with a + given authentication. Scores are on a range of 0-999, with 0 representing the + lowest risk and 999 representing the highest risk. For Visa transactions, + where the raw score has a range of 0-99, Lithic will normalize the score by + multiplying the raw score by 10x. + - `MESSAGE_CATEGORY`: The category of the authentication being processed. + """ + + operation: Optional[ + Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"] + ] = None + """The operation to apply to the attribute""" + + value: Union[str, int, List[str], None] = None + """A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`""" + + +class DraftVersionParametersConditional3DSActionParameters(BaseModel): + action: Literal["DECLINE", "CHALLENGE"] + """The action to take if the conditions are met.""" + + conditions: List[DraftVersionParametersConditional3DsActionParametersCondition] + + DraftVersionParameters: TypeAlias = Union[ - ConditionalBlockParameters, VelocityLimitParams, DraftVersionParametersMerchantLockParameters + ConditionalBlockParameters, + VelocityLimitParams, + DraftVersionParametersMerchantLockParameters, + DraftVersionParametersConditional3DSActionParameters, ] @@ -126,6 +246,9 @@ class V2UpdateResponse(BaseModel): draft_version: Optional[DraftVersion] = None + event_stream: Literal["AUTHORIZATION", "THREE_DS_AUTHENTICATION"] + """The type of event stream the Auth rule applies to.""" + name: Optional[str] = None """Auth Rule Name""" @@ -135,8 +258,16 @@ class V2UpdateResponse(BaseModel): state: Literal["ACTIVE", "INACTIVE"] """The state of the Auth Rule""" - type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK"] - """The type of Auth Rule""" + type: Literal["CONDITIONAL_BLOCK", "VELOCITY_LIMIT", "MERCHANT_LOCK", "CONDITIONAL_3DS_ACTION"] + """The type of Auth Rule. + + Effectively determines the event stream during which it will be evaluated. + + - `CONDITIONAL_BLOCK`: AUTHORIZATION event stream. + - `VELOCITY_LIMIT`: AUTHORIZATION event stream. + - `MERCHANT_LOCK`: AUTHORIZATION event stream. + - `CONDITIONAL_3DS_ACTION`: THREE_DS_AUTHENTICATION event stream. + """ excluded_card_tokens: Optional[List[str]] = None """Card tokens to which the Auth Rule does not apply.""" diff --git a/src/lithic/types/auth_rules/velocity_limit_params_period_window.py b/src/lithic/types/auth_rules/velocity_limit_params_period_window.py index 09db6bb2..9e9e25fe 100644 --- a/src/lithic/types/auth_rules/velocity_limit_params_period_window.py +++ b/src/lithic/types/auth_rules/velocity_limit_params_period_window.py @@ -4,4 +4,4 @@ __all__ = ["VelocityLimitParamsPeriodWindow"] -VelocityLimitParamsPeriodWindow: TypeAlias = Literal["DAY", "WEEK", "MONTH"] +VelocityLimitParamsPeriodWindow: TypeAlias = Literal["DAY", "WEEK", "MONTH", "YEAR"] diff --git a/src/lithic/types/financial_account.py b/src/lithic/types/financial_account.py index 88682948..db96c4dd 100644 --- a/src/lithic/types/financial_account.py +++ b/src/lithic/types/financial_account.py @@ -56,6 +56,7 @@ class FinancialAccount(BaseModel): "CHARGED_OFF_PRINCIPAL", "SECURITY", "PROGRAM_RECEIVABLES", + "COLLECTION", ] updated: datetime diff --git a/src/lithic/types/financial_account_register_account_number_params.py b/src/lithic/types/financial_account_register_account_number_params.py new file mode 100644 index 00000000..7611aaab --- /dev/null +++ b/src/lithic/types/financial_account_register_account_number_params.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["FinancialAccountRegisterAccountNumberParams"] + + +class FinancialAccountRegisterAccountNumberParams(TypedDict, total=False): + account_number: Required[str] diff --git a/src/lithic/types/funding_event_list_response.py b/src/lithic/types/funding_event_list_response.py index 83496225..74f0a5e4 100644 --- a/src/lithic/types/funding_event_list_response.py +++ b/src/lithic/types/funding_event_list_response.py @@ -6,13 +6,13 @@ from .._models import BaseModel -__all__ = ["FundingEventListResponse", "SettlementBreakdown"] +__all__ = ["FundingEventListResponse", "NetworkSettlementSummary"] -class SettlementBreakdown(BaseModel): - amount: int +class NetworkSettlementSummary(BaseModel): + network_settlement_date: date - settlement_date: date + settled_gross_amount: int class FundingEventListResponse(BaseModel): @@ -23,7 +23,10 @@ class FundingEventListResponse(BaseModel): """Collection resource type""" collection_tokens: List[str] - """IDs of collections""" + """ + IDs of collections, further information can be gathered from the appropriate + collection API based on collection_resource_type + """ created: datetime """Time of the creation""" @@ -31,11 +34,11 @@ class FundingEventListResponse(BaseModel): high_watermark: datetime """Time of the high watermark""" + network_settlement_summary: List[NetworkSettlementSummary] + """Network settlement summary breakdown by network settlement date""" + previous_high_watermark: datetime """Time of the previous high watermark""" - settlement_breakdowns: List[SettlementBreakdown] - """List of settlements""" - updated: datetime """Time of the update""" diff --git a/src/lithic/types/funding_event_retrieve_response.py b/src/lithic/types/funding_event_retrieve_response.py index bbac458a..b9d5b047 100644 --- a/src/lithic/types/funding_event_retrieve_response.py +++ b/src/lithic/types/funding_event_retrieve_response.py @@ -6,13 +6,13 @@ from .._models import BaseModel -__all__ = ["FundingEventRetrieveResponse", "SettlementBreakdown"] +__all__ = ["FundingEventRetrieveResponse", "NetworkSettlementSummary"] -class SettlementBreakdown(BaseModel): - amount: int +class NetworkSettlementSummary(BaseModel): + network_settlement_date: date - settlement_date: date + settled_gross_amount: int class FundingEventRetrieveResponse(BaseModel): @@ -23,7 +23,10 @@ class FundingEventRetrieveResponse(BaseModel): """Collection resource type""" collection_tokens: List[str] - """IDs of collections""" + """ + IDs of collections, further information can be gathered from the appropriate + collection API based on collection_resource_type + """ created: datetime """Time of the creation""" @@ -31,11 +34,11 @@ class FundingEventRetrieveResponse(BaseModel): high_watermark: datetime """Time of the high watermark""" + network_settlement_summary: List[NetworkSettlementSummary] + """Network settlement summary breakdown by network settlement date""" + previous_high_watermark: datetime """Time of the previous high watermark""" - settlement_breakdowns: List[SettlementBreakdown] - """List of settlements""" - updated: datetime """Time of the update""" diff --git a/src/lithic/types/payment.py b/src/lithic/types/payment.py index 7d58e7af..37171345 100644 --- a/src/lithic/types/payment.py +++ b/src/lithic/types/payment.py @@ -48,7 +48,7 @@ class Event(BaseModel): - `ACH_ORIGINATION_REVIEWED` - ACH origination has completed the review process. - `ACH_ORIGINATION_CANCELLED` - ACH origination has been cancelled. - `ACH_ORIGINATION_PROCESSED` - ACH origination has been processed and sent to - the fed. + the Federal Reserve. - `ACH_ORIGINATION_SETTLED` - ACH origination has settled. - `ACH_ORIGINATION_RELEASED` - ACH origination released from pending to available balance. diff --git a/src/lithic/types/required_document.py b/src/lithic/types/required_document.py index f1143f91..7bc70273 100644 --- a/src/lithic/types/required_document.py +++ b/src/lithic/types/required_document.py @@ -13,7 +13,7 @@ class RequiredDocument(BaseModel): status_reasons: List[str] """ - rovides the status reasons that will be satisfied by providing one of the valid + Provides the status reasons that will be satisfied by providing one of the valid documents. """ diff --git a/src/lithic/types/settlement_detail.py b/src/lithic/types/settlement_detail.py index 33df1023..aa661374 100644 --- a/src/lithic/types/settlement_detail.py +++ b/src/lithic/types/settlement_detail.py @@ -76,7 +76,11 @@ class SettlementDetail(BaseModel): """Date of when the report was first generated.""" settlement_date: str - """Date of when money movement is triggered for the transaction.""" + """Date of when money movement is triggered for the transaction. + + One exception applies - for Mastercard dual message settlement, this is the + settlement advisement date, which is distinct from the date of money movement. + """ transaction_token: str """Globally unique identifier denoting the associated Transaction object.""" diff --git a/src/lithic/types/shared/instance_financial_account_type.py b/src/lithic/types/shared/instance_financial_account_type.py index 4051b683..4e837f29 100644 --- a/src/lithic/types/shared/instance_financial_account_type.py +++ b/src/lithic/types/shared/instance_financial_account_type.py @@ -13,4 +13,5 @@ "CHARGED_OFF_PRINCIPAL", "SECURITY", "PROGRAM_RECEIVABLES", + "COLLECTION", ] diff --git a/src/lithic/types/transaction.py b/src/lithic/types/transaction.py index 6f5ec8ed..2b068bc3 100644 --- a/src/lithic/types/transaction.py +++ b/src/lithic/types/transaction.py @@ -119,7 +119,9 @@ class CardholderAuthentication(BaseModel): authentication_result: Literal["ATTEMPTS", "DECLINE", "NONE", "SUCCESS"] """Indicates what the outcome of the 3DS authentication process is.""" - decision_made_by: Literal["CUSTOMER_ENDPOINT", "LITHIC_DEFAULT", "LITHIC_RULES", "NETWORK", "UNKNOWN"] + decision_made_by: Literal[ + "CUSTOMER_RULES", "CUSTOMER_ENDPOINT", "LITHIC_DEFAULT", "LITHIC_RULES", "NETWORK", "UNKNOWN" + ] """Indicates which party made the 3DS authentication decision.""" liability_shift: Literal["3DS_AUTHENTICATED", "ACQUIRER_EXEMPTION", "NONE", "TOKEN_AUTHENTICATED"] @@ -719,7 +721,8 @@ class Transaction(BaseModel): acquirer_reference_number: Optional[str] = None """ Unique identifier assigned to a transaction by the acquirer that can be used in - dispute and chargeback filing. + dispute and chargeback filing. This field has been deprecated in favor of the + `acquirer_reference_number` that resides in the event-level `network_info`. """ amount: int diff --git a/src/lithic/types/verification_method.py b/src/lithic/types/verification_method.py index 72eae972..b9aa0ee1 100644 --- a/src/lithic/types/verification_method.py +++ b/src/lithic/types/verification_method.py @@ -4,4 +4,6 @@ __all__ = ["VerificationMethod"] -VerificationMethod: TypeAlias = Literal["MANUAL", "MICRO_DEPOSIT", "PLAID", "PRENOTE", "EXTERNALLY_VERIFIED"] +VerificationMethod: TypeAlias = Literal[ + "MANUAL", "MICRO_DEPOSIT", "PLAID", "PRENOTE", "EXTERNALLY_VERIFIED", "UNVERIFIED" +] diff --git a/tests/api_resources/auth_rules/test_v2.py b/tests/api_resources/auth_rules/test_v2.py index a86f4016..00505421 100644 --- a/tests/api_resources/auth_rules/test_v2.py +++ b/tests/api_resources/auth_rules/test_v2.py @@ -21,6 +21,8 @@ V2RetrieveResponse, ) +# pyright: reportDeprecated=false + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -369,6 +371,7 @@ def test_method_list_with_all_params(self, client: Lithic) -> None: account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", card_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ending_before="ending_before", + event_stream="AUTHORIZATION", page_size=1, scope="PROGRAM", starting_after="starting_after", @@ -435,18 +438,21 @@ def test_path_params_delete(self, client: Lithic) -> None: @parametrize def test_method_apply_overload_1(self, client: Lithic) -> None: - v2 = client.auth_rules.v2.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) + with pytest.warns(DeprecationWarning): + v2 = client.auth_rules.v2.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) + assert_matches_type(V2ApplyResponse, v2, path=["response"]) @parametrize def test_raw_response_apply_overload_1(self, client: Lithic) -> None: - response = client.auth_rules.v2.with_raw_response.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) + with pytest.warns(DeprecationWarning): + response = client.auth_rules.v2.with_raw_response.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -455,40 +461,45 @@ def test_raw_response_apply_overload_1(self, client: Lithic) -> None: @parametrize def test_streaming_response_apply_overload_1(self, client: Lithic) -> None: - with client.auth_rules.v2.with_streaming_response.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.auth_rules.v2.with_streaming_response.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - v2 = response.parse() - assert_matches_type(V2ApplyResponse, v2, path=["response"]) + v2 = response.parse() + assert_matches_type(V2ApplyResponse, v2, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_apply_overload_1(self, client: Lithic) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `auth_rule_token` but received ''"): - client.auth_rules.v2.with_raw_response.apply( - auth_rule_token="", - account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `auth_rule_token` but received ''"): + client.auth_rules.v2.with_raw_response.apply( + auth_rule_token="", + account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) @parametrize def test_method_apply_overload_2(self, client: Lithic) -> None: - v2 = client.auth_rules.v2.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) + with pytest.warns(DeprecationWarning): + v2 = client.auth_rules.v2.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) + assert_matches_type(V2ApplyResponse, v2, path=["response"]) @parametrize def test_raw_response_apply_overload_2(self, client: Lithic) -> None: - response = client.auth_rules.v2.with_raw_response.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) + with pytest.warns(DeprecationWarning): + response = client.auth_rules.v2.with_raw_response.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -497,49 +508,56 @@ def test_raw_response_apply_overload_2(self, client: Lithic) -> None: @parametrize def test_streaming_response_apply_overload_2(self, client: Lithic) -> None: - with client.auth_rules.v2.with_streaming_response.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.auth_rules.v2.with_streaming_response.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - v2 = response.parse() - assert_matches_type(V2ApplyResponse, v2, path=["response"]) + v2 = response.parse() + assert_matches_type(V2ApplyResponse, v2, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_apply_overload_2(self, client: Lithic) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `auth_rule_token` but received ''"): - client.auth_rules.v2.with_raw_response.apply( - auth_rule_token="", - card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `auth_rule_token` but received ''"): + client.auth_rules.v2.with_raw_response.apply( + auth_rule_token="", + card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) @parametrize def test_method_apply_overload_3(self, client: Lithic) -> None: - v2 = client.auth_rules.v2.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - program_level=True, - ) + with pytest.warns(DeprecationWarning): + v2 = client.auth_rules.v2.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + program_level=True, + ) + assert_matches_type(V2ApplyResponse, v2, path=["response"]) @parametrize def test_method_apply_with_all_params_overload_3(self, client: Lithic) -> None: - v2 = client.auth_rules.v2.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - program_level=True, - excluded_card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) + with pytest.warns(DeprecationWarning): + v2 = client.auth_rules.v2.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + program_level=True, + excluded_card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) + assert_matches_type(V2ApplyResponse, v2, path=["response"]) @parametrize def test_raw_response_apply_overload_3(self, client: Lithic) -> None: - response = client.auth_rules.v2.with_raw_response.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - program_level=True, - ) + with pytest.warns(DeprecationWarning): + response = client.auth_rules.v2.with_raw_response.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + program_level=True, + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -548,25 +566,27 @@ def test_raw_response_apply_overload_3(self, client: Lithic) -> None: @parametrize def test_streaming_response_apply_overload_3(self, client: Lithic) -> None: - with client.auth_rules.v2.with_streaming_response.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - program_level=True, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + with client.auth_rules.v2.with_streaming_response.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + program_level=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - v2 = response.parse() - assert_matches_type(V2ApplyResponse, v2, path=["response"]) + v2 = response.parse() + assert_matches_type(V2ApplyResponse, v2, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_apply_overload_3(self, client: Lithic) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `auth_rule_token` but received ''"): - client.auth_rules.v2.with_raw_response.apply( - auth_rule_token="", - program_level=True, - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `auth_rule_token` but received ''"): + client.auth_rules.v2.with_raw_response.apply( + auth_rule_token="", + program_level=True, + ) @parametrize def test_method_draft(self, client: Lithic) -> None: @@ -700,7 +720,9 @@ def test_path_params_report(self, client: Lithic) -> None: class TestAsyncV2: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_overload_1(self, async_client: AsyncLithic) -> None: @@ -1044,6 +1066,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncLithic) -> N account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", card_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ending_before="ending_before", + event_stream="AUTHORIZATION", page_size=1, scope="PROGRAM", starting_after="starting_after", @@ -1110,18 +1133,21 @@ async def test_path_params_delete(self, async_client: AsyncLithic) -> None: @parametrize async def test_method_apply_overload_1(self, async_client: AsyncLithic) -> None: - v2 = await async_client.auth_rules.v2.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) + with pytest.warns(DeprecationWarning): + v2 = await async_client.auth_rules.v2.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) + assert_matches_type(V2ApplyResponse, v2, path=["response"]) @parametrize async def test_raw_response_apply_overload_1(self, async_client: AsyncLithic) -> None: - response = await async_client.auth_rules.v2.with_raw_response.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) + with pytest.warns(DeprecationWarning): + response = await async_client.auth_rules.v2.with_raw_response.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1130,40 +1156,45 @@ async def test_raw_response_apply_overload_1(self, async_client: AsyncLithic) -> @parametrize async def test_streaming_response_apply_overload_1(self, async_client: AsyncLithic) -> None: - async with async_client.auth_rules.v2.with_streaming_response.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.auth_rules.v2.with_streaming_response.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - v2 = await response.parse() - assert_matches_type(V2ApplyResponse, v2, path=["response"]) + v2 = await response.parse() + assert_matches_type(V2ApplyResponse, v2, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_apply_overload_1(self, async_client: AsyncLithic) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `auth_rule_token` but received ''"): - await async_client.auth_rules.v2.with_raw_response.apply( - auth_rule_token="", - account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `auth_rule_token` but received ''"): + await async_client.auth_rules.v2.with_raw_response.apply( + auth_rule_token="", + account_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) @parametrize async def test_method_apply_overload_2(self, async_client: AsyncLithic) -> None: - v2 = await async_client.auth_rules.v2.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) + with pytest.warns(DeprecationWarning): + v2 = await async_client.auth_rules.v2.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) + assert_matches_type(V2ApplyResponse, v2, path=["response"]) @parametrize async def test_raw_response_apply_overload_2(self, async_client: AsyncLithic) -> None: - response = await async_client.auth_rules.v2.with_raw_response.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) + with pytest.warns(DeprecationWarning): + response = await async_client.auth_rules.v2.with_raw_response.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1172,49 +1203,56 @@ async def test_raw_response_apply_overload_2(self, async_client: AsyncLithic) -> @parametrize async def test_streaming_response_apply_overload_2(self, async_client: AsyncLithic) -> None: - async with async_client.auth_rules.v2.with_streaming_response.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.auth_rules.v2.with_streaming_response.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - v2 = await response.parse() - assert_matches_type(V2ApplyResponse, v2, path=["response"]) + v2 = await response.parse() + assert_matches_type(V2ApplyResponse, v2, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_apply_overload_2(self, async_client: AsyncLithic) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `auth_rule_token` but received ''"): - await async_client.auth_rules.v2.with_raw_response.apply( - auth_rule_token="", - card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `auth_rule_token` but received ''"): + await async_client.auth_rules.v2.with_raw_response.apply( + auth_rule_token="", + card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) @parametrize async def test_method_apply_overload_3(self, async_client: AsyncLithic) -> None: - v2 = await async_client.auth_rules.v2.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - program_level=True, - ) + with pytest.warns(DeprecationWarning): + v2 = await async_client.auth_rules.v2.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + program_level=True, + ) + assert_matches_type(V2ApplyResponse, v2, path=["response"]) @parametrize async def test_method_apply_with_all_params_overload_3(self, async_client: AsyncLithic) -> None: - v2 = await async_client.auth_rules.v2.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - program_level=True, - excluded_card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) + with pytest.warns(DeprecationWarning): + v2 = await async_client.auth_rules.v2.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + program_level=True, + excluded_card_tokens=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + ) + assert_matches_type(V2ApplyResponse, v2, path=["response"]) @parametrize async def test_raw_response_apply_overload_3(self, async_client: AsyncLithic) -> None: - response = await async_client.auth_rules.v2.with_raw_response.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - program_level=True, - ) + with pytest.warns(DeprecationWarning): + response = await async_client.auth_rules.v2.with_raw_response.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + program_level=True, + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1223,25 +1261,27 @@ async def test_raw_response_apply_overload_3(self, async_client: AsyncLithic) -> @parametrize async def test_streaming_response_apply_overload_3(self, async_client: AsyncLithic) -> None: - async with async_client.auth_rules.v2.with_streaming_response.apply( - auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - program_level=True, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" + with pytest.warns(DeprecationWarning): + async with async_client.auth_rules.v2.with_streaming_response.apply( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + program_level=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" - v2 = await response.parse() - assert_matches_type(V2ApplyResponse, v2, path=["response"]) + v2 = await response.parse() + assert_matches_type(V2ApplyResponse, v2, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_path_params_apply_overload_3(self, async_client: AsyncLithic) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `auth_rule_token` but received ''"): - await async_client.auth_rules.v2.with_raw_response.apply( - auth_rule_token="", - program_level=True, - ) + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `auth_rule_token` but received ''"): + await async_client.auth_rules.v2.with_raw_response.apply( + auth_rule_token="", + program_level=True, + ) @parametrize async def test_method_draft(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/auth_rules/v2/test_backtests.py b/tests/api_resources/auth_rules/v2/test_backtests.py index 12a05cec..851c4ff2 100644 --- a/tests/api_resources/auth_rules/v2/test_backtests.py +++ b/tests/api_resources/auth_rules/v2/test_backtests.py @@ -117,7 +117,9 @@ def test_path_params_retrieve(self, client: Lithic) -> None: class TestAsyncBacktests: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/cards/test_aggregate_balances.py b/tests/api_resources/cards/test_aggregate_balances.py index 79c01585..745e313d 100644 --- a/tests/api_resources/cards/test_aggregate_balances.py +++ b/tests/api_resources/cards/test_aggregate_balances.py @@ -53,7 +53,9 @@ def test_streaming_response_list(self, client: Lithic) -> None: class TestAsyncAggregateBalances: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/cards/test_balances.py b/tests/api_resources/cards/test_balances.py index 726066ea..63f50490 100644 --- a/tests/api_resources/cards/test_balances.py +++ b/tests/api_resources/cards/test_balances.py @@ -68,7 +68,9 @@ def test_path_params_list(self, client: Lithic) -> None: class TestAsyncBalances: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/cards/test_financial_transactions.py b/tests/api_resources/cards/test_financial_transactions.py index 7d3f5c06..16c512b6 100644 --- a/tests/api_resources/cards/test_financial_transactions.py +++ b/tests/api_resources/cards/test_financial_transactions.py @@ -123,7 +123,9 @@ def test_path_params_list(self, client: Lithic) -> None: class TestAsyncFinancialTransactions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/credit_products/test_extended_credit.py b/tests/api_resources/credit_products/test_extended_credit.py index 46b755db..15338e53 100644 --- a/tests/api_resources/credit_products/test_extended_credit.py +++ b/tests/api_resources/credit_products/test_extended_credit.py @@ -57,7 +57,9 @@ def test_path_params_retrieve(self, client: Lithic) -> None: class TestAsyncExtendedCredit: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/credit_products/test_prime_rates.py b/tests/api_resources/credit_products/test_prime_rates.py index 3534a8de..1c328156 100644 --- a/tests/api_resources/credit_products/test_prime_rates.py +++ b/tests/api_resources/credit_products/test_prime_rates.py @@ -113,7 +113,9 @@ def test_path_params_retrieve(self, client: Lithic) -> None: class TestAsyncPrimeRates: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/events/test_event_subscriptions.py b/tests/api_resources/events/test_event_subscriptions.py index a8d7f749..710e7893 100644 --- a/tests/api_resources/events/test_event_subscriptions.py +++ b/tests/api_resources/events/test_event_subscriptions.py @@ -67,7 +67,9 @@ def test_path_params_resend(self, client: Lithic) -> None: class TestAsyncEventSubscriptions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_resend(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/events/test_subscriptions.py b/tests/api_resources/events/test_subscriptions.py index 307bc14d..4b8d45cd 100644 --- a/tests/api_resources/events/test_subscriptions.py +++ b/tests/api_resources/events/test_subscriptions.py @@ -531,7 +531,9 @@ def test_path_params_send_simulated_example(self, client: Lithic) -> None: class TestAsyncSubscriptions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/external_bank_accounts/test_micro_deposits.py b/tests/api_resources/external_bank_accounts/test_micro_deposits.py index 679c9865..8513afa9 100644 --- a/tests/api_resources/external_bank_accounts/test_micro_deposits.py +++ b/tests/api_resources/external_bank_accounts/test_micro_deposits.py @@ -63,7 +63,9 @@ def test_path_params_create(self, client: Lithic) -> None: class TestAsyncMicroDeposits: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/financial_accounts/statements/test_line_items.py b/tests/api_resources/financial_accounts/statements/test_line_items.py index 842282fd..3b5fd860 100644 --- a/tests/api_resources/financial_accounts/statements/test_line_items.py +++ b/tests/api_resources/financial_accounts/statements/test_line_items.py @@ -81,7 +81,9 @@ def test_path_params_list(self, client: Lithic) -> None: class TestAsyncLineItems: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/financial_accounts/test_balances.py b/tests/api_resources/financial_accounts/test_balances.py index 6f5ac9f2..db71f8f9 100644 --- a/tests/api_resources/financial_accounts/test_balances.py +++ b/tests/api_resources/financial_accounts/test_balances.py @@ -70,7 +70,9 @@ def test_path_params_list(self, client: Lithic) -> None: class TestAsyncBalances: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/financial_accounts/test_credit_configuration.py b/tests/api_resources/financial_accounts/test_credit_configuration.py index 98e8d545..a88de2b8 100644 --- a/tests/api_resources/financial_accounts/test_credit_configuration.py +++ b/tests/api_resources/financial_accounts/test_credit_configuration.py @@ -110,7 +110,9 @@ def test_path_params_update(self, client: Lithic) -> None: class TestAsyncCreditConfiguration: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/financial_accounts/test_financial_transactions.py b/tests/api_resources/financial_accounts/test_financial_transactions.py index efa82133..7bc8a301 100644 --- a/tests/api_resources/financial_accounts/test_financial_transactions.py +++ b/tests/api_resources/financial_accounts/test_financial_transactions.py @@ -127,7 +127,9 @@ def test_path_params_list(self, client: Lithic) -> None: class TestAsyncFinancialTransactions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/financial_accounts/test_loan_tapes.py b/tests/api_resources/financial_accounts/test_loan_tapes.py index c64e0e66..dd935ec9 100644 --- a/tests/api_resources/financial_accounts/test_loan_tapes.py +++ b/tests/api_resources/financial_accounts/test_loan_tapes.py @@ -123,7 +123,9 @@ def test_path_params_list(self, client: Lithic) -> None: class TestAsyncLoanTapes: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/financial_accounts/test_statements.py b/tests/api_resources/financial_accounts/test_statements.py index 20752a11..f7f27d48 100644 --- a/tests/api_resources/financial_accounts/test_statements.py +++ b/tests/api_resources/financial_accounts/test_statements.py @@ -124,7 +124,9 @@ def test_path_params_list(self, client: Lithic) -> None: class TestAsyncStatements: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/reports/settlement/test_network_totals.py b/tests/api_resources/reports/settlement/test_network_totals.py index 7a247d61..acd5a25f 100644 --- a/tests/api_resources/reports/settlement/test_network_totals.py +++ b/tests/api_resources/reports/settlement/test_network_totals.py @@ -104,7 +104,9 @@ def test_streaming_response_list(self, client: Lithic) -> None: class TestAsyncNetworkTotals: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/reports/test_settlement.py b/tests/api_resources/reports/test_settlement.py index 57e78cde..b3d5c3d6 100644 --- a/tests/api_resources/reports/test_settlement.py +++ b/tests/api_resources/reports/test_settlement.py @@ -107,7 +107,9 @@ def test_path_params_summary(self, client: Lithic) -> None: class TestAsyncSettlement: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list_details(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/test_account_holders.py b/tests/api_resources/test_account_holders.py index e813c3fd..ccd60ff8 100644 --- a/tests/api_resources/test_account_holders.py +++ b/tests/api_resources/test_account_holders.py @@ -993,7 +993,9 @@ def test_path_params_upload_document(self, client: Lithic) -> None: class TestAsyncAccountHolders: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_overload_1(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/test_accounts.py b/tests/api_resources/test_accounts.py index 601d8d31..ef56f643 100644 --- a/tests/api_resources/test_accounts.py +++ b/tests/api_resources/test_accounts.py @@ -195,7 +195,9 @@ def test_path_params_retrieve_spend_limits(self, client: Lithic) -> None: class TestAsyncAccounts: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_aggregate_balances.py b/tests/api_resources/test_aggregate_balances.py index ab692037..485f951f 100644 --- a/tests/api_resources/test_aggregate_balances.py +++ b/tests/api_resources/test_aggregate_balances.py @@ -52,7 +52,9 @@ def test_streaming_response_list(self, client: Lithic) -> None: class TestAsyncAggregateBalances: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/test_auth_stream_enrollment.py b/tests/api_resources/test_auth_stream_enrollment.py index 6405a48a..7e7c97f4 100644 --- a/tests/api_resources/test_auth_stream_enrollment.py +++ b/tests/api_resources/test_auth_stream_enrollment.py @@ -69,7 +69,9 @@ def test_streaming_response_rotate_secret(self, client: Lithic) -> None: class TestAsyncAuthStreamEnrollment: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_retrieve_secret(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/test_balances.py b/tests/api_resources/test_balances.py index 57b39a42..6db2188b 100644 --- a/tests/api_resources/test_balances.py +++ b/tests/api_resources/test_balances.py @@ -56,7 +56,9 @@ def test_streaming_response_list(self, client: Lithic) -> None: class TestAsyncBalances: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_list(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/test_book_transfers.py b/tests/api_resources/test_book_transfers.py index 5880bdc9..34879210 100644 --- a/tests/api_resources/test_book_transfers.py +++ b/tests/api_resources/test_book_transfers.py @@ -209,7 +209,9 @@ def test_path_params_reverse(self, client: Lithic) -> None: class TestAsyncBookTransfers: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_card_programs.py b/tests/api_resources/test_card_programs.py index 362db573..9c32d3c7 100644 --- a/tests/api_resources/test_card_programs.py +++ b/tests/api_resources/test_card_programs.py @@ -92,7 +92,9 @@ def test_streaming_response_list(self, client: Lithic) -> None: class TestAsyncCardPrograms: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_cards.py b/tests/api_resources/test_cards.py index b537a90a..56149df3 100644 --- a/tests/api_resources/test_cards.py +++ b/tests/api_resources/test_cards.py @@ -691,7 +691,9 @@ def test_path_params_web_provision(self, client: Lithic) -> None: class TestAsyncCards: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_client.py b/tests/api_resources/test_client.py index 339a1212..804fc259 100644 --- a/tests/api_resources/test_client.py +++ b/tests/api_resources/test_client.py @@ -44,7 +44,9 @@ def test_streaming_response_api_status(self, client: Lithic) -> None: class TestAsyncClient: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_api_status(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/test_digital_card_art.py b/tests/api_resources/test_digital_card_art.py index b46cd04f..7c873768 100644 --- a/tests/api_resources/test_digital_card_art.py +++ b/tests/api_resources/test_digital_card_art.py @@ -94,7 +94,9 @@ def test_streaming_response_list(self, client: Lithic) -> None: class TestAsyncDigitalCardArt: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_disputes.py b/tests/api_resources/test_disputes.py index 01f9e422..28821e5c 100644 --- a/tests/api_resources/test_disputes.py +++ b/tests/api_resources/test_disputes.py @@ -427,7 +427,9 @@ def test_path_params_retrieve_evidence(self, client: Lithic) -> None: class TestAsyncDisputes: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_events.py b/tests/api_resources/test_events.py index 37ad8993..0f74ba88 100644 --- a/tests/api_resources/test_events.py +++ b/tests/api_resources/test_events.py @@ -155,7 +155,9 @@ def test_method_resend(self, client: Lithic) -> None: class TestAsyncEvents: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_external_bank_accounts.py b/tests/api_resources/test_external_bank_accounts.py index bdb409d2..172ab15a 100644 --- a/tests/api_resources/test_external_bank_accounts.py +++ b/tests/api_resources/test_external_bank_accounts.py @@ -489,7 +489,9 @@ def test_path_params_retry_prenote(self, client: Lithic) -> None: class TestAsyncExternalBankAccounts: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_overload_1(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/test_external_payments.py b/tests/api_resources/test_external_payments.py index 2d2e1e49..1f36397d 100644 --- a/tests/api_resources/test_external_payments.py +++ b/tests/api_resources/test_external_payments.py @@ -375,7 +375,9 @@ def test_path_params_settle(self, client: Lithic) -> None: class TestAsyncExternalPayments: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_financial_accounts.py b/tests/api_resources/test_financial_accounts.py index dc79f4dc..b490ddb3 100644 --- a/tests/api_resources/test_financial_accounts.py +++ b/tests/api_resources/test_financial_accounts.py @@ -186,6 +186,50 @@ def test_streaming_response_list(self, client: Lithic) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_register_account_number(self, client: Lithic) -> None: + financial_account = client.financial_accounts.register_account_number( + financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + account_number="account_number", + ) + assert financial_account is None + + @parametrize + def test_raw_response_register_account_number(self, client: Lithic) -> None: + response = client.financial_accounts.with_raw_response.register_account_number( + financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + account_number="account_number", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + financial_account = response.parse() + assert financial_account is None + + @parametrize + def test_streaming_response_register_account_number(self, client: Lithic) -> None: + with client.financial_accounts.with_streaming_response.register_account_number( + financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + account_number="account_number", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + financial_account = response.parse() + assert financial_account is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_register_account_number(self, client: Lithic) -> None: + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `financial_account_token` but received ''" + ): + client.financial_accounts.with_raw_response.register_account_number( + financial_account_token="", + account_number="account_number", + ) + @parametrize def test_method_update_status(self, client: Lithic) -> None: financial_account = client.financial_accounts.update_status( @@ -236,7 +280,9 @@ def test_path_params_update_status(self, client: Lithic) -> None: class TestAsyncFinancialAccounts: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: @@ -404,6 +450,50 @@ async def test_streaming_response_list(self, async_client: AsyncLithic) -> None: assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_register_account_number(self, async_client: AsyncLithic) -> None: + financial_account = await async_client.financial_accounts.register_account_number( + financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + account_number="account_number", + ) + assert financial_account is None + + @parametrize + async def test_raw_response_register_account_number(self, async_client: AsyncLithic) -> None: + response = await async_client.financial_accounts.with_raw_response.register_account_number( + financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + account_number="account_number", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + financial_account = response.parse() + assert financial_account is None + + @parametrize + async def test_streaming_response_register_account_number(self, async_client: AsyncLithic) -> None: + async with async_client.financial_accounts.with_streaming_response.register_account_number( + financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + account_number="account_number", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + financial_account = await response.parse() + assert financial_account is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_register_account_number(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.with_raw_response.register_account_number( + financial_account_token="", + account_number="account_number", + ) + @parametrize async def test_method_update_status(self, async_client: AsyncLithic) -> None: financial_account = await async_client.financial_accounts.update_status( diff --git a/tests/api_resources/test_funding_events.py b/tests/api_resources/test_funding_events.py index 62c547e8..ee78113e 100644 --- a/tests/api_resources/test_funding_events.py +++ b/tests/api_resources/test_funding_events.py @@ -134,7 +134,9 @@ def test_path_params_retrieve_details(self, client: Lithic) -> None: class TestAsyncFundingEvents: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_management_operations.py b/tests/api_resources/test_management_operations.py index 6288fda4..1199fa53 100644 --- a/tests/api_resources/test_management_operations.py +++ b/tests/api_resources/test_management_operations.py @@ -218,7 +218,9 @@ def test_path_params_reverse(self, client: Lithic) -> None: class TestAsyncManagementOperations: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_payments.py b/tests/api_resources/test_payments.py index e556f11a..f409a78f 100644 --- a/tests/api_resources/test_payments.py +++ b/tests/api_resources/test_payments.py @@ -381,7 +381,9 @@ def test_streaming_response_simulate_return(self, client: Lithic) -> None: class TestAsyncPayments: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_responder_endpoints.py b/tests/api_resources/test_responder_endpoints.py index 53555059..beb88d7e 100644 --- a/tests/api_resources/test_responder_endpoints.py +++ b/tests/api_resources/test_responder_endpoints.py @@ -120,7 +120,9 @@ def test_streaming_response_check_status(self, client: Lithic) -> None: class TestAsyncResponderEndpoints: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_tokenization_decisioning.py b/tests/api_resources/test_tokenization_decisioning.py index b20f6cfa..5dae2a06 100644 --- a/tests/api_resources/test_tokenization_decisioning.py +++ b/tests/api_resources/test_tokenization_decisioning.py @@ -71,7 +71,9 @@ def test_streaming_response_rotate_secret(self, client: Lithic) -> None: class TestAsyncTokenizationDecisioning: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_retrieve_secret(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/test_tokenizations.py b/tests/api_resources/test_tokenizations.py index cb3402ac..b69a1d58 100644 --- a/tests/api_resources/test_tokenizations.py +++ b/tests/api_resources/test_tokenizations.py @@ -401,7 +401,9 @@ def test_path_params_update_digital_card_art(self, client: Lithic) -> None: class TestAsyncTokenizations: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_transactions.py b/tests/api_resources/test_transactions.py index b0f32521..df884ff3 100644 --- a/tests/api_resources/test_transactions.py +++ b/tests/api_resources/test_transactions.py @@ -428,7 +428,9 @@ def test_streaming_response_simulate_void(self, client: Lithic) -> None: class TestAsyncTransactions: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/three_ds/test_authentication.py b/tests/api_resources/three_ds/test_authentication.py index 466818f5..afc195f1 100644 --- a/tests/api_resources/three_ds/test_authentication.py +++ b/tests/api_resources/three_ds/test_authentication.py @@ -175,7 +175,9 @@ def test_streaming_response_simulate_otp_entry(self, client: Lithic) -> None: class TestAsyncAuthentication: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/three_ds/test_decisioning.py b/tests/api_resources/three_ds/test_decisioning.py index 6a0a392e..53a0bc0f 100644 --- a/tests/api_resources/three_ds/test_decisioning.py +++ b/tests/api_resources/three_ds/test_decisioning.py @@ -105,7 +105,9 @@ def test_streaming_response_rotate_secret(self, client: Lithic) -> None: class TestAsyncDecisioning: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_challenge_response(self, async_client: AsyncLithic) -> None: diff --git a/tests/api_resources/transactions/events/test_enhanced_commercial_data.py b/tests/api_resources/transactions/events/test_enhanced_commercial_data.py index a9eb3ce9..b668d10f 100644 --- a/tests/api_resources/transactions/events/test_enhanced_commercial_data.py +++ b/tests/api_resources/transactions/events/test_enhanced_commercial_data.py @@ -57,7 +57,9 @@ def test_path_params_retrieve(self, client: Lithic) -> None: class TestAsyncEnhancedCommercialData: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/transactions/test_enhanced_commercial_data.py b/tests/api_resources/transactions/test_enhanced_commercial_data.py index 7330e2e5..bd9a2e4b 100644 --- a/tests/api_resources/transactions/test_enhanced_commercial_data.py +++ b/tests/api_resources/transactions/test_enhanced_commercial_data.py @@ -57,7 +57,9 @@ def test_path_params_retrieve(self, client: Lithic) -> None: class TestAsyncEnhancedCommercialData: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/conftest.py b/tests/conftest.py index 4de50f30..4a50dc5d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,13 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + from __future__ import annotations import os import logging from typing import TYPE_CHECKING, Iterator, AsyncIterator +import httpx import pytest from pytest_asyncio import is_async_test -from lithic import Lithic, AsyncLithic +from lithic import Lithic, AsyncLithic, DefaultAioHttpClient +from lithic._utils import is_dict if TYPE_CHECKING: from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage] @@ -25,6 +29,19 @@ def pytest_collection_modifyitems(items: list[pytest.Function]) -> None: for async_test in pytest_asyncio_tests: async_test.add_marker(session_scope_marker, append=False) + # We skip tests that use both the aiohttp client and respx_mock as respx_mock + # doesn't support custom transports. + for item in items: + if "async_client" not in item.fixturenames or "respx_mock" not in item.fixturenames: + continue + + if not hasattr(item, "callspec"): + continue + + async_client_param = item.callspec.params.get("async_client") + if is_dict(async_client_param) and async_client_param.get("http_client") == "aiohttp": + item.add_marker(pytest.mark.skip(reason="aiohttp client is not compatible with respx_mock")) + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -43,9 +60,25 @@ def client(request: FixtureRequest) -> Iterator[Lithic]: @pytest.fixture(scope="session") async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncLithic]: - strict = getattr(request, "param", True) - if not isinstance(strict, bool): - raise TypeError(f"Unexpected fixture parameter type {type(strict)}, expected {bool}") - - async with AsyncLithic(base_url=base_url, api_key=api_key, _strict_response_validation=strict) as client: + param = getattr(request, "param", True) + + # defaults + strict = True + http_client: None | httpx.AsyncClient = None + + if isinstance(param, bool): + strict = param + elif is_dict(param): + strict = param.get("strict", True) + assert isinstance(strict, bool) + + http_client_type = param.get("http_client", "httpx") + if http_client_type == "aiohttp": + http_client = DefaultAioHttpClient() + else: + raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict") + + async with AsyncLithic( + base_url=base_url, api_key=api_key, _strict_response_validation=strict, http_client=http_client + ) as client: yield client diff --git a/tests/test_client.py b/tests/test_client.py index 2ab10ad2..3623482c 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -23,12 +23,16 @@ from lithic import Lithic, AsyncLithic, APIResponseValidationError from lithic._types import Omit -from lithic._utils import maybe_transform from lithic._models import BaseModel, FinalRequestOptions -from lithic._constants import RAW_RESPONSE_HEADER from lithic._exceptions import LithicError, APIStatusError, APITimeoutError, APIResponseValidationError -from lithic._base_client import DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, BaseClient, make_request_options -from lithic.types.card_create_params import CardCreateParams +from lithic._base_client import ( + DEFAULT_TIMEOUT, + HTTPX_DEFAULT_TIMEOUT, + BaseClient, + DefaultHttpxClient, + DefaultAsyncHttpxClient, + make_request_options, +) from .utils import update_env @@ -187,6 +191,7 @@ def test_copy_signature(self) -> None: copy_param = copy_signature.parameters.get(name) assert copy_param is not None, f"copy() signature is missing the {name} param" + @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") def test_copy_build_request(self) -> None: options = FinalRequestOptions(method="get", url="/foo") @@ -714,32 +719,21 @@ def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str @mock.patch("lithic._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: Lithic) -> None: respx_mock.post("/v1/cards").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - self.client.post( - "/v1/cards", - body=cast(object, maybe_transform(dict(type="SINGLE_USE"), CardCreateParams)), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) + client.cards.with_streaming_response.create(type="VIRTUAL").__enter__() assert _get_open_connections(self.client) == 0 @mock.patch("lithic._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: Lithic) -> None: respx_mock.post("/v1/cards").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - self.client.post( - "/v1/cards", - body=cast(object, maybe_transform(dict(type="SINGLE_USE"), CardCreateParams)), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) - + client.cards.with_streaming_response.create(type="VIRTUAL").__enter__() assert _get_open_connections(self.client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @@ -846,6 +840,55 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + 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") + + client = DefaultHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + + @pytest.mark.respx(base_url=base_url) + def test_follow_redirects(self, respx_mock: MockRouter) -> None: + # Test that the default follow_redirects=True allows following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) + + response = self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + assert response.status_code == 200 + assert response.json() == {"status": "ok"} + + @pytest.mark.respx(base_url=base_url) + def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + # Test that follow_redirects=False prevents following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + + with pytest.raises(APIStatusError) as exc_info: + self.client.post( + "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response + ) + + assert exc_info.value.response.status_code == 302 + assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" + class TestAsyncLithic: client = AsyncLithic(base_url=base_url, api_key=api_key, _strict_response_validation=True) @@ -982,6 +1025,7 @@ def test_copy_signature(self) -> None: copy_param = copy_signature.parameters.get(name) assert copy_param is not None, f"copy() signature is missing the {name} param" + @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") def test_copy_build_request(self) -> None: options = FinalRequestOptions(method="get", url="/foo") @@ -1527,32 +1571,21 @@ async def test_parse_retry_after_header(self, remaining_retries: int, retry_afte @mock.patch("lithic._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncLithic) -> None: respx_mock.post("/v1/cards").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - await self.client.post( - "/v1/cards", - body=cast(object, maybe_transform(dict(type="SINGLE_USE"), CardCreateParams)), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) + await async_client.cards.with_streaming_response.create(type="VIRTUAL").__aenter__() assert _get_open_connections(self.client) == 0 @mock.patch("lithic._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncLithic) -> None: respx_mock.post("/v1/cards").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - await self.client.post( - "/v1/cards", - body=cast(object, maybe_transform(dict(type="SINGLE_USE"), CardCreateParams)), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) - + await async_client.cards.with_streaming_response.create(type="VIRTUAL").__aenter__() assert _get_open_connections(self.client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @@ -1707,3 +1740,52 @@ async def test_main() -> None: raise AssertionError("calling get_platform using asyncify resulted in a hung process") time.sleep(0.1) + + 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") + + client = DefaultAsyncHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + async def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultAsyncHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + + @pytest.mark.respx(base_url=base_url) + async def test_follow_redirects(self, respx_mock: MockRouter) -> None: + # Test that the default follow_redirects=True allows following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) + + response = await self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + assert response.status_code == 200 + assert response.json() == {"status": "ok"} + + @pytest.mark.respx(base_url=base_url) + async def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + # Test that follow_redirects=False prevents following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + + with pytest.raises(APIStatusError) as exc_info: + await self.client.post( + "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response + ) + + assert exc_info.value.response.status_code == 302 + assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected"