diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b6a32348..1219cf77 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,7 @@ jobs: timeout-minutes: 10 name: lint runs-on: ${{ github.repository == 'stainless-sdks/lithic-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 @@ -35,7 +36,7 @@ jobs: run: ./scripts/lint upload: - if: github.repository == 'stainless-sdks/lithic-python' + if: github.repository == 'stainless-sdks/lithic-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) timeout-minutes: 10 name: upload permissions: @@ -62,6 +63,7 @@ jobs: timeout-minutes: 10 name: test runs-on: ${{ github.repository == 'stainless-sdks/lithic-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 @@ -83,7 +85,7 @@ jobs: timeout-minutes: 10 name: examples runs-on: ${{ github.repository == 'stainless-sdks/lithic-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.repository == 'lithic-com/lithic-python' + if: github.repository == 'lithic-com/lithic-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) steps: - uses: actions/checkout@v4 diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 91393ed8..2292ca70 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.94.0" + ".": "0.95.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 2d0fb2d5..ba657b97 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -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 +configured_endpoints: 164 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-aa684ff2a2af585fe502a6e44520ddd883f5141a1113fc9dbe7830027842aa09.yml +openapi_spec_hash: b58989fdc04768fc1eb758e180c5f128 +config_hash: 1a83dceb58f6f525b19a5775018db7e8 diff --git a/CHANGELOG.md b/CHANGELOG.md index e7085981..dd41ec7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## 0.95.0 (2025-06-29) + +Full Changelog: [v0.94.0...v0.95.0](https://github.com/lithic-com/lithic-python/compare/v0.94.0...v0.95.0) + +### Features + +* **api:** introduce dedicated model for SpendLimitDuration ([1e1fb23](https://github.com/lithic-com/lithic-python/commit/1e1fb237a754aeb2a3d9cc5b751ef5d4c51d11e9)) +* **client:** adds support for on-demand Auth Rule Performance Reports ([81c2860](https://github.com/lithic-com/lithic-python/commit/81c2860a37078364b3f4c1876f407b60bdb88bec)) + + +### Bug Fixes + +* **ci:** correct conditional ([9422f2e](https://github.com/lithic-com/lithic-python/commit/9422f2ec8393447429219af34bda88c581984fa3)) +* **ci:** release-doctor — report correct token name ([59781eb](https://github.com/lithic-com/lithic-python/commit/59781ebf072b0b0839d0ad4ab27a79bfa045db59)) + + +### Chores + +* **ci:** only run for pushes and fork pull requests ([954c7f0](https://github.com/lithic-com/lithic-python/commit/954c7f0f1bea593b30d71d15a8c626ffadf30c6b)) +* **internal:** manual updates ([0c5bbdb](https://github.com/lithic-com/lithic-python/commit/0c5bbdb7e2bff6f7588b06b5ef3ed40db06b412b)) + ## 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) diff --git a/api.md b/api.md index 323fabf8..5a10a649 100644 --- a/api.md +++ b/api.md @@ -83,6 +83,7 @@ from lithic.types.auth_rules import ( AuthRuleCondition, ConditionalAttribute, ConditionalBlockParameters, + RuleStats, VelocityLimitParams, VelocityLimitParamsPeriodWindow, V2CreateResponse, @@ -93,6 +94,7 @@ from lithic.types.auth_rules import ( V2DraftResponse, V2PromoteResponse, V2ReportResponse, + V2RetrieveReportResponse, ) ``` @@ -107,6 +109,7 @@ Methods: - client.auth_rules.v2.draft(auth_rule_token, \*\*params) -> V2DraftResponse - client.auth_rules.v2.promote(auth_rule_token) -> V2PromoteResponse - client.auth_rules.v2.report(auth_rule_token) -> V2ReportResponse +- client.auth_rules.v2.retrieve_report(auth_rule_token, \*\*params) -> V2RetrieveReportResponse ### Backtests @@ -734,3 +737,18 @@ Methods: - client.funding_events.retrieve(funding_event_token) -> FundingEventRetrieveResponse - client.funding_events.list(\*\*params) -> SyncCursorPage[FundingEventListResponse] - client.funding_events.retrieve_details(funding_event_token) -> FundingEventRetrieveDetailsResponse + +# Fraud + +## Transactions + +Types: + +```python +from lithic.types.fraud import TransactionRetrieveResponse, TransactionReportResponse +``` + +Methods: + +- client.fraud.transactions.retrieve(transaction_token) -> TransactionRetrieveResponse +- client.fraud.transactions.report(transaction_token, \*\*params) -> TransactionReportResponse diff --git a/bin/check-release-environment b/bin/check-release-environment index 075f33e3..b845b0f4 100644 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -3,7 +3,7 @@ errors=() if [ -z "${PYPI_TOKEN}" ]; then - errors+=("The LITHIC_PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") + errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") fi lenErrors=${#errors[@]} diff --git a/pyproject.toml b/pyproject.toml index 71756fe2..7a00f8d6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "lithic" -version = "0.94.0" +version = "0.95.0" description = "The official Python library for the lithic API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/lithic/_client.py b/src/lithic/_client.py index 1e97d5c2..04f3d4c0 100644 --- a/src/lithic/_client.py +++ b/src/lithic/_client.py @@ -39,6 +39,7 @@ if TYPE_CHECKING: from .resources import ( cards, + fraud, events, reports, accounts, @@ -70,6 +71,7 @@ from .resources.disputes import Disputes, AsyncDisputes from .resources.payments import Payments, AsyncPayments from .resources.cards.cards import Cards, AsyncCards + from .resources.fraud.fraud import Fraud, AsyncFraud from .resources.card_programs import CardPrograms, AsyncCardPrograms from .resources.events.events import Events, AsyncEvents from .resources.tokenizations import Tokenizations, AsyncTokenizations @@ -352,6 +354,12 @@ def webhooks(self) -> webhooks.Webhooks: return Webhooks(self) + @cached_property + def fraud(self) -> Fraud: + from .resources.fraud import Fraud + + return Fraud(self) + @cached_property def with_raw_response(self) -> LithicWithRawResponse: return LithicWithRawResponse(self) @@ -726,6 +734,12 @@ def funding_events(self) -> AsyncFundingEvents: return AsyncFundingEvents(self) + @cached_property + def fraud(self) -> AsyncFraud: + from .resources.fraud import AsyncFraud + + return AsyncFraud(self) + @cached_property def webhooks(self) -> webhooks.AsyncWebhooks: from .resources.webhooks import AsyncWebhooks @@ -1029,6 +1043,12 @@ def funding_events(self) -> funding_events.FundingEventsWithRawResponse: return FundingEventsWithRawResponse(self._client.funding_events) + @cached_property + def fraud(self) -> fraud.FraudWithRawResponse: + from .resources.fraud import FraudWithRawResponse + + return FraudWithRawResponse(self._client.fraud) + class AsyncLithicWithRawResponse: _client: AsyncLithic @@ -1190,6 +1210,12 @@ def funding_events(self) -> funding_events.AsyncFundingEventsWithRawResponse: return AsyncFundingEventsWithRawResponse(self._client.funding_events) + @cached_property + def fraud(self) -> fraud.AsyncFraudWithRawResponse: + from .resources.fraud import AsyncFraudWithRawResponse + + return AsyncFraudWithRawResponse(self._client.fraud) + class LithicWithStreamedResponse: _client: Lithic @@ -1351,6 +1377,12 @@ def funding_events(self) -> funding_events.FundingEventsWithStreamingResponse: return FundingEventsWithStreamingResponse(self._client.funding_events) + @cached_property + def fraud(self) -> fraud.FraudWithStreamingResponse: + from .resources.fraud import FraudWithStreamingResponse + + return FraudWithStreamingResponse(self._client.fraud) + class AsyncLithicWithStreamedResponse: _client: AsyncLithic @@ -1512,6 +1544,12 @@ def funding_events(self) -> funding_events.AsyncFundingEventsWithStreamingRespon return AsyncFundingEventsWithStreamingResponse(self._client.funding_events) + @cached_property + def fraud(self) -> fraud.AsyncFraudWithStreamingResponse: + from .resources.fraud import AsyncFraudWithStreamingResponse + + return AsyncFraudWithStreamingResponse(self._client.fraud) + Client = Lithic diff --git a/src/lithic/_version.py b/src/lithic/_version.py index 7cfff106..6dbf48d0 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.94.0" # x-release-please-version +__version__ = "0.95.0" # x-release-please-version diff --git a/src/lithic/resources/__init__.py b/src/lithic/resources/__init__.py index 6186ee94..4aeeec9b 100644 --- a/src/lithic/resources/__init__.py +++ b/src/lithic/resources/__init__.py @@ -8,6 +8,14 @@ CardsWithStreamingResponse, AsyncCardsWithStreamingResponse, ) +from .fraud import ( + Fraud, + AsyncFraud, + FraudWithRawResponse, + AsyncFraudWithRawResponse, + FraudWithStreamingResponse, + AsyncFraudWithStreamingResponse, +) from .events import ( Events, AsyncEvents, @@ -355,4 +363,10 @@ "AsyncFundingEventsWithRawResponse", "FundingEventsWithStreamingResponse", "AsyncFundingEventsWithStreamingResponse", + "Fraud", + "AsyncFraud", + "FraudWithRawResponse", + "AsyncFraudWithRawResponse", + "FraudWithStreamingResponse", + "AsyncFraudWithStreamingResponse", ] diff --git a/src/lithic/resources/auth_rules/v2/backtests.py b/src/lithic/resources/auth_rules/v2/backtests.py index ae5e9db0..760c4a37 100644 --- a/src/lithic/resources/auth_rules/v2/backtests.py +++ b/src/lithic/resources/auth_rules/v2/backtests.py @@ -72,13 +72,14 @@ def create( `/v2/auth_rules/{auth_rule_token}/backtests/{auth_rule_backtest_token}` endpoint. - Lithic currently supports backtesting for `CONDITIONAL_BLOCK` rules. Backtesting - for `VELOCITY_LIMIT` rules is generally not supported. In specific cases (i.e. - where Lithic has pre-calculated the requested velocity metrics for historical - transactions), a backtest may be feasible. However, such cases are uncommon and - customers should not anticipate support for velocity backtests under most - configurations. If a historical transaction does not feature the required inputs - to evaluate the rule, then it will not be included in the final backtest report. + Lithic currently supports backtesting for `CONDITIONAL_BLOCK` / + `CONDITIONAL_3DS_ACTION` rules. Backtesting for `VELOCITY_LIMIT` rules is + generally not supported. In specific cases (i.e. where Lithic has pre-calculated + the requested velocity metrics for historical transactions), a backtest may be + feasible. However, such cases are uncommon and customers should not anticipate + support for velocity backtests under most configurations. If a historical + transaction does not feature the required inputs to evaluate the rule, then it + will not be included in the final backtest report. Args: end: The end time of the backtest. @@ -217,13 +218,14 @@ async def create( `/v2/auth_rules/{auth_rule_token}/backtests/{auth_rule_backtest_token}` endpoint. - Lithic currently supports backtesting for `CONDITIONAL_BLOCK` rules. Backtesting - for `VELOCITY_LIMIT` rules is generally not supported. In specific cases (i.e. - where Lithic has pre-calculated the requested velocity metrics for historical - transactions), a backtest may be feasible. However, such cases are uncommon and - customers should not anticipate support for velocity backtests under most - configurations. If a historical transaction does not feature the required inputs - to evaluate the rule, then it will not be included in the final backtest report. + Lithic currently supports backtesting for `CONDITIONAL_BLOCK` / + `CONDITIONAL_3DS_ACTION` rules. Backtesting for `VELOCITY_LIMIT` rules is + generally not supported. In specific cases (i.e. where Lithic has pre-calculated + the requested velocity metrics for historical transactions), a backtest may be + feasible. However, such cases are uncommon and customers should not anticipate + support for velocity backtests under most configurations. If a historical + transaction does not feature the required inputs to evaluate the rule, then it + will not be included in the final backtest report. Args: end: The end time of the backtest. diff --git a/src/lithic/resources/auth_rules/v2/v2.py b/src/lithic/resources/auth_rules/v2/v2.py index fd793e41..3d3f89cc 100644 --- a/src/lithic/resources/auth_rules/v2/v2.py +++ b/src/lithic/resources/auth_rules/v2/v2.py @@ -3,7 +3,8 @@ from __future__ import annotations import typing_extensions -from typing import List, Optional +from typing import List, Union, Optional +from datetime import date from typing_extensions import Literal, overload import httpx @@ -24,7 +25,14 @@ from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper from ....pagination import SyncCursorPage, AsyncCursorPage from ...._base_client import AsyncPaginator, make_request_options -from ....types.auth_rules import v2_list_params, v2_apply_params, v2_draft_params, v2_create_params, v2_update_params +from ....types.auth_rules import ( + v2_list_params, + v2_apply_params, + v2_draft_params, + v2_create_params, + v2_update_params, + v2_retrieve_report_params, +) from ....types.auth_rules.v2_list_response import V2ListResponse from ....types.auth_rules.v2_apply_response import V2ApplyResponse from ....types.auth_rules.v2_draft_response import V2DraftResponse @@ -33,6 +41,7 @@ from ....types.auth_rules.v2_update_response import V2UpdateResponse from ....types.auth_rules.v2_promote_response import V2PromoteResponse from ....types.auth_rules.v2_retrieve_response import V2RetrieveResponse +from ....types.auth_rules.v2_retrieve_report_response import V2RetrieveReportResponse __all__ = ["V2", "AsyncV2"] @@ -752,6 +761,7 @@ def promote( cast_to=V2PromoteResponse, ) + @typing_extensions.deprecated("deprecated") def report( self, auth_rule_token: str, @@ -763,11 +773,13 @@ def report( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2ReportResponse: - """ - 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` = + """This endpoint is deprecated and will be removed in the future. + + 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). @@ -834,6 +846,67 @@ def report( cast_to=V2ReportResponse, ) + def retrieve_report( + self, + auth_rule_token: str, + *, + begin: Union[str, date], + end: Union[str, date], + # 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, + ) -> V2RetrieveReportResponse: + """ + Retrieves a performance report for an Auth rule containing daily statistics and + evaluation outcomes. + + **Time Range Limitations:** + + - Reports are supported for the past 3 months only + - Maximum interval length is 1 month + - Report data is available only through the previous day in UTC (current day + data is not available) + + The report provides daily statistics for both current and draft versions of the + Auth rule, including approval, decline, and challenge counts along with sample + events. + + Args: + begin: Start date for the report + + end: End date for the report + + 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 auth_rule_token: + raise ValueError(f"Expected a non-empty value for `auth_rule_token` but received {auth_rule_token!r}") + return self._get( + f"/v2/auth_rules/{auth_rule_token}/report", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "begin": begin, + "end": end, + }, + v2_retrieve_report_params.V2RetrieveReportParams, + ), + ), + cast_to=V2RetrieveReportResponse, + ) + class AsyncV2(AsyncAPIResource): @cached_property @@ -1550,6 +1623,7 @@ async def promote( cast_to=V2PromoteResponse, ) + @typing_extensions.deprecated("deprecated") async def report( self, auth_rule_token: str, @@ -1561,11 +1635,13 @@ async def report( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> V2ReportResponse: - """ - 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` = + """This endpoint is deprecated and will be removed in the future. + + 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). @@ -1632,6 +1708,67 @@ async def report( cast_to=V2ReportResponse, ) + async def retrieve_report( + self, + auth_rule_token: str, + *, + begin: Union[str, date], + end: Union[str, date], + # 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, + ) -> V2RetrieveReportResponse: + """ + Retrieves a performance report for an Auth rule containing daily statistics and + evaluation outcomes. + + **Time Range Limitations:** + + - Reports are supported for the past 3 months only + - Maximum interval length is 1 month + - Report data is available only through the previous day in UTC (current day + data is not available) + + The report provides daily statistics for both current and draft versions of the + Auth rule, including approval, decline, and challenge counts along with sample + events. + + Args: + begin: Start date for the report + + end: End date for the report + + 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 auth_rule_token: + raise ValueError(f"Expected a non-empty value for `auth_rule_token` but received {auth_rule_token!r}") + return await self._get( + f"/v2/auth_rules/{auth_rule_token}/report", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "begin": begin, + "end": end, + }, + v2_retrieve_report_params.V2RetrieveReportParams, + ), + ), + cast_to=V2RetrieveReportResponse, + ) + class V2WithRawResponse: def __init__(self, v2: V2) -> None: @@ -1663,8 +1800,13 @@ def __init__(self, v2: V2) -> None: self.promote = _legacy_response.to_raw_response_wrapper( v2.promote, ) - self.report = _legacy_response.to_raw_response_wrapper( - v2.report, + self.report = ( # pyright: ignore[reportDeprecated] + _legacy_response.to_raw_response_wrapper( + v2.report # pyright: ignore[reportDeprecated], + ) + ) + self.retrieve_report = _legacy_response.to_raw_response_wrapper( + v2.retrieve_report, ) @cached_property @@ -1702,8 +1844,13 @@ def __init__(self, v2: AsyncV2) -> None: self.promote = _legacy_response.async_to_raw_response_wrapper( v2.promote, ) - self.report = _legacy_response.async_to_raw_response_wrapper( - v2.report, + self.report = ( # pyright: ignore[reportDeprecated] + _legacy_response.async_to_raw_response_wrapper( + v2.report # pyright: ignore[reportDeprecated], + ) + ) + self.retrieve_report = _legacy_response.async_to_raw_response_wrapper( + v2.retrieve_report, ) @cached_property @@ -1741,8 +1888,13 @@ def __init__(self, v2: V2) -> None: self.promote = to_streamed_response_wrapper( v2.promote, ) - self.report = to_streamed_response_wrapper( - v2.report, + self.report = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + v2.report # pyright: ignore[reportDeprecated], + ) + ) + self.retrieve_report = to_streamed_response_wrapper( + v2.retrieve_report, ) @cached_property @@ -1780,8 +1932,13 @@ def __init__(self, v2: AsyncV2) -> None: self.promote = async_to_streamed_response_wrapper( v2.promote, ) - self.report = async_to_streamed_response_wrapper( - v2.report, + self.report = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + v2.report # pyright: ignore[reportDeprecated], + ) + ) + self.retrieve_report = async_to_streamed_response_wrapper( + v2.retrieve_report, ) @cached_property diff --git a/src/lithic/resources/cards/cards.py b/src/lithic/resources/cards/cards.py index 231704c7..6794a99d 100644 --- a/src/lithic/resources/cards/cards.py +++ b/src/lithic/resources/cards/cards.py @@ -206,10 +206,12 @@ def create( - `STANDARD_WITH_TRACKING` - USPS regular mail or similar international option, with tracking - `PRIORITY` - USPS Priority, 1-3 day shipping, with tracking - - `EXPRESS` - FedEx Express, 3-day shipping, with tracking - - `2_DAY` - FedEx 2-day shipping, with tracking - - `EXPEDITED` - FedEx Standard Overnight or similar international option, with + - `EXPRESS` - FedEx or UPS depending on card manufacturer, Express, 3-day + shipping, with tracking + - `2_DAY` - FedEx or UPS depending on card manufacturer, 2-day shipping, with tracking + - `EXPEDITED` - FedEx or UPS depending on card manufacturer, Standard Overnight + or similar international option, with tracking spend_limit: Amount (in cents) to limit approved authorizations (e.g. 100000 would be a $1,000 limit). Transaction requests above the spend limit will be declined. Note @@ -532,10 +534,12 @@ def convert_physical( - `STANDARD_WITH_TRACKING` - USPS regular mail or similar international option, with tracking - `PRIORITY` - USPS Priority, 1-3 day shipping, with tracking - - `EXPRESS` - FedEx Express, 3-day shipping, with tracking - - `2_DAY` - FedEx 2-day shipping, with tracking - - `EXPEDITED` - FedEx Standard Overnight or similar international option, with + - `EXPRESS` - FedEx or UPS depending on card manufacturer, Express, 3-day + shipping, with tracking + - `2_DAY` - FedEx or UPS depending on card manufacturer, 2-day shipping, with tracking + - `EXPEDITED` - FedEx or UPS depending on card manufacturer, Standard Overnight + or similar international option, with tracking extra_headers: Send extra headers @@ -867,10 +871,12 @@ def reissue( - `STANDARD_WITH_TRACKING` - USPS regular mail or similar international option, with tracking - `PRIORITY` - USPS Priority, 1-3 day shipping, with tracking - - `EXPRESS` - FedEx Express, 3-day shipping, with tracking - - `2_DAY` - FedEx 2-day shipping, with tracking - - `EXPEDITED` - FedEx Standard Overnight or similar international option, with + - `EXPRESS` - FedEx or UPS depending on card manufacturer, Express, 3-day + shipping, with tracking + - `2_DAY` - FedEx or UPS depending on card manufacturer, 2-day shipping, with tracking + - `EXPEDITED` - FedEx or UPS depending on card manufacturer, Standard Overnight + or similar international option, with tracking extra_headers: Send extra headers @@ -952,10 +958,12 @@ def renew( - `STANDARD_WITH_TRACKING` - USPS regular mail or similar international option, with tracking - `PRIORITY` - USPS Priority, 1-3 day shipping, with tracking - - `EXPRESS` - FedEx Express, 3-day shipping, with tracking - - `2_DAY` - FedEx 2-day shipping, with tracking - - `EXPEDITED` - FedEx Standard Overnight or similar international option, with + - `EXPRESS` - FedEx or UPS depending on card manufacturer, Express, 3-day + shipping, with tracking + - `2_DAY` - FedEx or UPS depending on card manufacturer, 2-day shipping, with tracking + - `EXPEDITED` - FedEx or UPS depending on card manufacturer, Standard Overnight + or similar international option, with tracking extra_headers: Send extra headers @@ -1239,10 +1247,12 @@ async def create( - `STANDARD_WITH_TRACKING` - USPS regular mail or similar international option, with tracking - `PRIORITY` - USPS Priority, 1-3 day shipping, with tracking - - `EXPRESS` - FedEx Express, 3-day shipping, with tracking - - `2_DAY` - FedEx 2-day shipping, with tracking - - `EXPEDITED` - FedEx Standard Overnight or similar international option, with + - `EXPRESS` - FedEx or UPS depending on card manufacturer, Express, 3-day + shipping, with tracking + - `2_DAY` - FedEx or UPS depending on card manufacturer, 2-day shipping, with tracking + - `EXPEDITED` - FedEx or UPS depending on card manufacturer, Standard Overnight + or similar international option, with tracking spend_limit: Amount (in cents) to limit approved authorizations (e.g. 100000 would be a $1,000 limit). Transaction requests above the spend limit will be declined. Note @@ -1565,10 +1575,12 @@ async def convert_physical( - `STANDARD_WITH_TRACKING` - USPS regular mail or similar international option, with tracking - `PRIORITY` - USPS Priority, 1-3 day shipping, with tracking - - `EXPRESS` - FedEx Express, 3-day shipping, with tracking - - `2_DAY` - FedEx 2-day shipping, with tracking - - `EXPEDITED` - FedEx Standard Overnight or similar international option, with + - `EXPRESS` - FedEx or UPS depending on card manufacturer, Express, 3-day + shipping, with tracking + - `2_DAY` - FedEx or UPS depending on card manufacturer, 2-day shipping, with tracking + - `EXPEDITED` - FedEx or UPS depending on card manufacturer, Standard Overnight + or similar international option, with tracking extra_headers: Send extra headers @@ -1900,10 +1912,12 @@ async def reissue( - `STANDARD_WITH_TRACKING` - USPS regular mail or similar international option, with tracking - `PRIORITY` - USPS Priority, 1-3 day shipping, with tracking - - `EXPRESS` - FedEx Express, 3-day shipping, with tracking - - `2_DAY` - FedEx 2-day shipping, with tracking - - `EXPEDITED` - FedEx Standard Overnight or similar international option, with + - `EXPRESS` - FedEx or UPS depending on card manufacturer, Express, 3-day + shipping, with tracking + - `2_DAY` - FedEx or UPS depending on card manufacturer, 2-day shipping, with tracking + - `EXPEDITED` - FedEx or UPS depending on card manufacturer, Standard Overnight + or similar international option, with tracking extra_headers: Send extra headers @@ -1985,10 +1999,12 @@ async def renew( - `STANDARD_WITH_TRACKING` - USPS regular mail or similar international option, with tracking - `PRIORITY` - USPS Priority, 1-3 day shipping, with tracking - - `EXPRESS` - FedEx Express, 3-day shipping, with tracking - - `2_DAY` - FedEx 2-day shipping, with tracking - - `EXPEDITED` - FedEx Standard Overnight or similar international option, with + - `EXPRESS` - FedEx or UPS depending on card manufacturer, Express, 3-day + shipping, with tracking + - `2_DAY` - FedEx or UPS depending on card manufacturer, 2-day shipping, with tracking + - `EXPEDITED` - FedEx or UPS depending on card manufacturer, Standard Overnight + or similar international option, with tracking extra_headers: Send extra headers diff --git a/src/lithic/resources/external_bank_accounts/external_bank_accounts.py b/src/lithic/resources/external_bank_accounts/external_bank_accounts.py index 03fd2188..4805c971 100644 --- a/src/lithic/resources/external_bank_accounts/external_bank_accounts.py +++ b/src/lithic/resources/external_bank_accounts/external_bank_accounts.py @@ -275,6 +275,80 @@ def create( """ ... + @overload + def create( + self, + *, + account_number: str, + country: str, + currency: str, + owner: str, + owner_type: OwnerType, + routing_number: str, + type: Literal["CHECKING", "SAVINGS"], + verification_method: Literal["UNVERIFIED"], + account_token: str | NotGiven = NOT_GIVEN, + address: ExternalBankAccountAddressParam | NotGiven = NOT_GIVEN, + company_id: str | NotGiven = NOT_GIVEN, + dob: Union[str, date] | NotGiven = NOT_GIVEN, + doing_business_as: str | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + user_defined_id: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ExternalBankAccountCreateResponse: + """ + Creates an external bank account within a program or Lithic account. + + Args: + account_number: Account Number + + country: The country that the bank account is located in using ISO 3166-1. We will only + accept USA bank accounts e.g., USA + + currency: currency of the external account 3-character alphabetic ISO 4217 code + + owner: Legal Name of the business or individual who owns the external account. This + will appear in statements + + owner_type: Owner Type + + routing_number: Routing Number + + type: Account Type + + verification_method: Verification Method + + account_token: Indicates which Lithic account the external account is associated with. For + external accounts that are associated with the program, account_token field + returned will be null + + address: Address + + company_id: Optional field that helps identify bank accounts in receipts + + dob: Date of Birth of the Individual that owns the external bank account + + doing_business_as: Doing Business As + + name: The nickname for this External Bank Account + + user_defined_id: User Defined ID + + 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 + """ + ... + @required_args( [ "account_number", @@ -310,7 +384,7 @@ def create( owner_type: OwnerType, routing_number: str | NotGiven = NOT_GIVEN, type: Literal["CHECKING", "SAVINGS"] | NotGiven = NOT_GIVEN, - verification_method: VerificationMethod | Literal["EXTERNALLY_VERIFIED"], + verification_method: VerificationMethod | Literal["EXTERNALLY_VERIFIED"] | Literal["UNVERIFIED"], account_token: str | NotGiven = NOT_GIVEN, address: ExternalBankAccountAddressParam | NotGiven = NOT_GIVEN, company_id: str | NotGiven = NOT_GIVEN, @@ -844,6 +918,80 @@ async def create( """ ... + @overload + async def create( + self, + *, + account_number: str, + country: str, + currency: str, + owner: str, + owner_type: OwnerType, + routing_number: str, + type: Literal["CHECKING", "SAVINGS"], + verification_method: Literal["UNVERIFIED"], + account_token: str | NotGiven = NOT_GIVEN, + address: ExternalBankAccountAddressParam | NotGiven = NOT_GIVEN, + company_id: str | NotGiven = NOT_GIVEN, + dob: Union[str, date] | NotGiven = NOT_GIVEN, + doing_business_as: str | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + user_defined_id: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ExternalBankAccountCreateResponse: + """ + Creates an external bank account within a program or Lithic account. + + Args: + account_number: Account Number + + country: The country that the bank account is located in using ISO 3166-1. We will only + accept USA bank accounts e.g., USA + + currency: currency of the external account 3-character alphabetic ISO 4217 code + + owner: Legal Name of the business or individual who owns the external account. This + will appear in statements + + owner_type: Owner Type + + routing_number: Routing Number + + type: Account Type + + verification_method: Verification Method + + account_token: Indicates which Lithic account the external account is associated with. For + external accounts that are associated with the program, account_token field + returned will be null + + address: Address + + company_id: Optional field that helps identify bank accounts in receipts + + dob: Date of Birth of the Individual that owns the external bank account + + doing_business_as: Doing Business As + + name: The nickname for this External Bank Account + + user_defined_id: User Defined ID + + 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 + """ + ... + @required_args( [ "account_number", @@ -879,7 +1027,7 @@ async def create( owner_type: OwnerType, routing_number: str | NotGiven = NOT_GIVEN, type: Literal["CHECKING", "SAVINGS"] | NotGiven = NOT_GIVEN, - verification_method: VerificationMethod | Literal["EXTERNALLY_VERIFIED"], + verification_method: VerificationMethod | Literal["EXTERNALLY_VERIFIED"] | Literal["UNVERIFIED"], account_token: str | NotGiven = NOT_GIVEN, address: ExternalBankAccountAddressParam | NotGiven = NOT_GIVEN, company_id: str | NotGiven = NOT_GIVEN, diff --git a/src/lithic/resources/fraud/__init__.py b/src/lithic/resources/fraud/__init__.py new file mode 100644 index 00000000..5ebcc75e --- /dev/null +++ b/src/lithic/resources/fraud/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .fraud import ( + Fraud, + AsyncFraud, + FraudWithRawResponse, + AsyncFraudWithRawResponse, + FraudWithStreamingResponse, + AsyncFraudWithStreamingResponse, +) +from .transactions import ( + Transactions, + AsyncTransactions, + TransactionsWithRawResponse, + AsyncTransactionsWithRawResponse, + TransactionsWithStreamingResponse, + AsyncTransactionsWithStreamingResponse, +) + +__all__ = [ + "Transactions", + "AsyncTransactions", + "TransactionsWithRawResponse", + "AsyncTransactionsWithRawResponse", + "TransactionsWithStreamingResponse", + "AsyncTransactionsWithStreamingResponse", + "Fraud", + "AsyncFraud", + "FraudWithRawResponse", + "AsyncFraudWithRawResponse", + "FraudWithStreamingResponse", + "AsyncFraudWithStreamingResponse", +] diff --git a/src/lithic/resources/fraud/fraud.py b/src/lithic/resources/fraud/fraud.py new file mode 100644 index 00000000..ba851033 --- /dev/null +++ b/src/lithic/resources/fraud/fraud.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from .transactions import ( + Transactions, + AsyncTransactions, + TransactionsWithRawResponse, + AsyncTransactionsWithRawResponse, + TransactionsWithStreamingResponse, + AsyncTransactionsWithStreamingResponse, +) + +__all__ = ["Fraud", "AsyncFraud"] + + +class Fraud(SyncAPIResource): + @cached_property + def transactions(self) -> Transactions: + return Transactions(self._client) + + @cached_property + def with_raw_response(self) -> FraudWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/lithic-com/lithic-python#accessing-raw-response-data-eg-headers + """ + return FraudWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FraudWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/lithic-com/lithic-python#with_streaming_response + """ + return FraudWithStreamingResponse(self) + + +class AsyncFraud(AsyncAPIResource): + @cached_property + def transactions(self) -> AsyncTransactions: + return AsyncTransactions(self._client) + + @cached_property + def with_raw_response(self) -> AsyncFraudWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/lithic-com/lithic-python#accessing-raw-response-data-eg-headers + """ + return AsyncFraudWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFraudWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/lithic-com/lithic-python#with_streaming_response + """ + return AsyncFraudWithStreamingResponse(self) + + +class FraudWithRawResponse: + def __init__(self, fraud: Fraud) -> None: + self._fraud = fraud + + @cached_property + def transactions(self) -> TransactionsWithRawResponse: + return TransactionsWithRawResponse(self._fraud.transactions) + + +class AsyncFraudWithRawResponse: + def __init__(self, fraud: AsyncFraud) -> None: + self._fraud = fraud + + @cached_property + def transactions(self) -> AsyncTransactionsWithRawResponse: + return AsyncTransactionsWithRawResponse(self._fraud.transactions) + + +class FraudWithStreamingResponse: + def __init__(self, fraud: Fraud) -> None: + self._fraud = fraud + + @cached_property + def transactions(self) -> TransactionsWithStreamingResponse: + return TransactionsWithStreamingResponse(self._fraud.transactions) + + +class AsyncFraudWithStreamingResponse: + def __init__(self, fraud: AsyncFraud) -> None: + self._fraud = fraud + + @cached_property + def transactions(self) -> AsyncTransactionsWithStreamingResponse: + return AsyncTransactionsWithStreamingResponse(self._fraud.transactions) diff --git a/src/lithic/resources/fraud/transactions.py b/src/lithic/resources/fraud/transactions.py new file mode 100644 index 00000000..3ec3e274 --- /dev/null +++ b/src/lithic/resources/fraud/transactions.py @@ -0,0 +1,348 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ... import _legacy_response +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ...types.fraud import transaction_report_params +from ..._base_client import make_request_options +from ...types.fraud.transaction_report_response import TransactionReportResponse +from ...types.fraud.transaction_retrieve_response import TransactionRetrieveResponse + +__all__ = ["Transactions", "AsyncTransactions"] + + +class Transactions(SyncAPIResource): + @cached_property + def with_raw_response(self) -> TransactionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/lithic-com/lithic-python#accessing-raw-response-data-eg-headers + """ + return TransactionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TransactionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/lithic-com/lithic-python#with_streaming_response + """ + return TransactionsWithStreamingResponse(self) + + def retrieve( + self, + transaction_token: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> TransactionRetrieveResponse: + """ + Retrieve a fraud report for a specific transaction identified by its unique + transaction token. + + 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 transaction_token: + raise ValueError(f"Expected a non-empty value for `transaction_token` but received {transaction_token!r}") + return self._get( + f"/v1/fraud/transactions/{transaction_token}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TransactionRetrieveResponse, + ) + + def report( + self, + transaction_token: str, + *, + fraud_status: Literal["SUSPECTED_FRAUD", "FRAUDULENT", "NOT_FRAUDULENT"], + comment: str | NotGiven = NOT_GIVEN, + fraud_type: Literal[ + "FIRST_PARTY_FRAUD", "ACCOUNT_TAKEOVER", "CARD_COMPROMISED", "IDENTITY_THEFT", "CARDHOLDER_MANIPULATION" + ] + | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> TransactionReportResponse: + """ + Report fraud for a specific transaction token by providing details such as fraud + type, fraud status, and any additional comments. + + Args: + fraud_status: The fraud status of the transaction, string (enum) supporting the following + values: + + - `SUSPECTED_FRAUD`: The transaction is suspected to be fraudulent, but this + hasn’t been confirmed. + - `FRAUDULENT`: The transaction is confirmed to be fraudulent. A transaction may + immediately be moved into this state, or be graduated into this state from the + `SUSPECTED_FRAUD` state. + - `NOT_FRAUDULENT`: The transaction is (explicitly) marked as not fraudulent. A + transaction may immediately be moved into this state, or be graduated into + this state from the `SUSPECTED_FRAUD` state. + + comment: Optional field providing additional information or context about why the + transaction is considered fraudulent. + + fraud_type: Specifies the type or category of fraud that the transaction is suspected or + confirmed to involve, string (enum) supporting the following values: + + - `FIRST_PARTY_FRAUD`: First-party fraud occurs when a legitimate account or + cardholder intentionally misuses financial services for personal gain. This + includes actions such as disputing legitimate transactions to obtain a refund, + abusing return policies, or defaulting on credit obligations without intent to + repay. + - `ACCOUNT_TAKEOVER`: Account takeover fraud occurs when a fraudster gains + unauthorized access to an existing account, modifies account settings, and + carries out fraudulent transactions. + - `CARD_COMPROMISED`: Card compromised fraud occurs when a fraudster gains + access to card details without taking over the account, such as through + physical card theft, cloning, or online data breaches. + - `IDENTITY_THEFT`: Identity theft fraud occurs when a fraudster uses stolen + personal information, such as Social Security numbers or addresses, to open + accounts, apply for loans, or conduct financial transactions in someone's + name. + - `CARDHOLDER_MANIPULATION`: This type of fraud occurs when a fraudster + manipulates or coerces a legitimate cardholder into unauthorized transactions, + often through social engineering tactics. + + 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 transaction_token: + raise ValueError(f"Expected a non-empty value for `transaction_token` but received {transaction_token!r}") + return self._post( + f"/v1/fraud/transactions/{transaction_token}", + body=maybe_transform( + { + "fraud_status": fraud_status, + "comment": comment, + "fraud_type": fraud_type, + }, + transaction_report_params.TransactionReportParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TransactionReportResponse, + ) + + +class AsyncTransactions(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncTransactionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/lithic-com/lithic-python#accessing-raw-response-data-eg-headers + """ + return AsyncTransactionsWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTransactionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/lithic-com/lithic-python#with_streaming_response + """ + return AsyncTransactionsWithStreamingResponse(self) + + async def retrieve( + self, + transaction_token: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> TransactionRetrieveResponse: + """ + Retrieve a fraud report for a specific transaction identified by its unique + transaction token. + + 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 transaction_token: + raise ValueError(f"Expected a non-empty value for `transaction_token` but received {transaction_token!r}") + return await self._get( + f"/v1/fraud/transactions/{transaction_token}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TransactionRetrieveResponse, + ) + + async def report( + self, + transaction_token: str, + *, + fraud_status: Literal["SUSPECTED_FRAUD", "FRAUDULENT", "NOT_FRAUDULENT"], + comment: str | NotGiven = NOT_GIVEN, + fraud_type: Literal[ + "FIRST_PARTY_FRAUD", "ACCOUNT_TAKEOVER", "CARD_COMPROMISED", "IDENTITY_THEFT", "CARDHOLDER_MANIPULATION" + ] + | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> TransactionReportResponse: + """ + Report fraud for a specific transaction token by providing details such as fraud + type, fraud status, and any additional comments. + + Args: + fraud_status: The fraud status of the transaction, string (enum) supporting the following + values: + + - `SUSPECTED_FRAUD`: The transaction is suspected to be fraudulent, but this + hasn’t been confirmed. + - `FRAUDULENT`: The transaction is confirmed to be fraudulent. A transaction may + immediately be moved into this state, or be graduated into this state from the + `SUSPECTED_FRAUD` state. + - `NOT_FRAUDULENT`: The transaction is (explicitly) marked as not fraudulent. A + transaction may immediately be moved into this state, or be graduated into + this state from the `SUSPECTED_FRAUD` state. + + comment: Optional field providing additional information or context about why the + transaction is considered fraudulent. + + fraud_type: Specifies the type or category of fraud that the transaction is suspected or + confirmed to involve, string (enum) supporting the following values: + + - `FIRST_PARTY_FRAUD`: First-party fraud occurs when a legitimate account or + cardholder intentionally misuses financial services for personal gain. This + includes actions such as disputing legitimate transactions to obtain a refund, + abusing return policies, or defaulting on credit obligations without intent to + repay. + - `ACCOUNT_TAKEOVER`: Account takeover fraud occurs when a fraudster gains + unauthorized access to an existing account, modifies account settings, and + carries out fraudulent transactions. + - `CARD_COMPROMISED`: Card compromised fraud occurs when a fraudster gains + access to card details without taking over the account, such as through + physical card theft, cloning, or online data breaches. + - `IDENTITY_THEFT`: Identity theft fraud occurs when a fraudster uses stolen + personal information, such as Social Security numbers or addresses, to open + accounts, apply for loans, or conduct financial transactions in someone's + name. + - `CARDHOLDER_MANIPULATION`: This type of fraud occurs when a fraudster + manipulates or coerces a legitimate cardholder into unauthorized transactions, + often through social engineering tactics. + + 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 transaction_token: + raise ValueError(f"Expected a non-empty value for `transaction_token` but received {transaction_token!r}") + return await self._post( + f"/v1/fraud/transactions/{transaction_token}", + body=await async_maybe_transform( + { + "fraud_status": fraud_status, + "comment": comment, + "fraud_type": fraud_type, + }, + transaction_report_params.TransactionReportParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TransactionReportResponse, + ) + + +class TransactionsWithRawResponse: + def __init__(self, transactions: Transactions) -> None: + self._transactions = transactions + + self.retrieve = _legacy_response.to_raw_response_wrapper( + transactions.retrieve, + ) + self.report = _legacy_response.to_raw_response_wrapper( + transactions.report, + ) + + +class AsyncTransactionsWithRawResponse: + def __init__(self, transactions: AsyncTransactions) -> None: + self._transactions = transactions + + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + transactions.retrieve, + ) + self.report = _legacy_response.async_to_raw_response_wrapper( + transactions.report, + ) + + +class TransactionsWithStreamingResponse: + def __init__(self, transactions: Transactions) -> None: + self._transactions = transactions + + self.retrieve = to_streamed_response_wrapper( + transactions.retrieve, + ) + self.report = to_streamed_response_wrapper( + transactions.report, + ) + + +class AsyncTransactionsWithStreamingResponse: + def __init__(self, transactions: AsyncTransactions) -> None: + self._transactions = transactions + + self.retrieve = async_to_streamed_response_wrapper( + transactions.retrieve, + ) + self.report = async_to_streamed_response_wrapper( + transactions.report, + ) diff --git a/src/lithic/resources/three_ds/authentication.py b/src/lithic/resources/three_ds/authentication.py index 81b628cf..789b7498 100644 --- a/src/lithic/resources/three_ds/authentication.py +++ b/src/lithic/resources/three_ds/authentication.py @@ -98,8 +98,12 @@ def simulate( has a valid phone number configured to receive the OTP code via SMS. Args: + merchant: Merchant information for the simulated transaction + pan: Sixteen digit card number. + transaction: Transaction details for the simulation + card_expiry_check: When set will use the following values as part of the Simulated Authentication. When not set defaults to MATCH @@ -143,9 +147,9 @@ def simulate_otp_entry( """Endpoint for simulating entering OTP into 3DS Challenge UI. A call to - /v1/three_ds_authentication/simulate that resulted in triggered SMS-OTP - challenge must precede. Only a single attempt is supported; upon entering OTP, - the challenge is either approved or declined. + [/v1/three_ds_authentication/simulate](https://docs.lithic.com/reference/postsimulateauthentication) + that resulted in triggered SMS-OTP challenge must precede. Only a single attempt + is supported; upon entering OTP, the challenge is either approved or declined. Args: token: A unique token returned as part of a /v1/three_ds_authentication/simulate call @@ -255,8 +259,12 @@ async def simulate( has a valid phone number configured to receive the OTP code via SMS. Args: + merchant: Merchant information for the simulated transaction + pan: Sixteen digit card number. + transaction: Transaction details for the simulation + card_expiry_check: When set will use the following values as part of the Simulated Authentication. When not set defaults to MATCH @@ -300,9 +308,9 @@ async def simulate_otp_entry( """Endpoint for simulating entering OTP into 3DS Challenge UI. A call to - /v1/three_ds_authentication/simulate that resulted in triggered SMS-OTP - challenge must precede. Only a single attempt is supported; upon entering OTP, - the challenge is either approved or declined. + [/v1/three_ds_authentication/simulate](https://docs.lithic.com/reference/postsimulateauthentication) + that resulted in triggered SMS-OTP challenge must precede. Only a single attempt + is supported; upon entering OTP, the challenge is either approved or declined. Args: token: A unique token returned as part of a /v1/three_ds_authentication/simulate call diff --git a/src/lithic/resources/three_ds/decisioning.py b/src/lithic/resources/three_ds/decisioning.py index c9721bc6..7ad3a088 100644 --- a/src/lithic/resources/three_ds/decisioning.py +++ b/src/lithic/resources/three_ds/decisioning.py @@ -50,16 +50,20 @@ def challenge_response( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> None: - """ - Card program's response to a 3DS Challenge Request (CReq) + """Card program's response to a 3DS Challenge Request. + + Challenge Request is emitted + as a webhook + [three_ds_authentication.challenge](https://docs.lithic.com/reference/post_three-ds-authentication-challenge) + and your Card Program needs to be configured with Out of Band (OOB) Challenges + in order to receive it (see https://docs.lithic.com/docs/3ds-challenge-flow for + more information). Args: - token: Globally unique identifier for the 3DS authentication. This token is sent as - part of the initial 3DS Decisioning Request and as part of the 3DS Challenge - Event in the [ThreeDSAuthentication](#/components/schemas/ThreeDSAuthentication) - object + token: Globally unique identifier for 3DS Authentication that resulted in + PENDING_CHALLENGE authentication result. - challenge_response: Whether the Cardholder has Approved or Declined the issued Challenge + challenge_response: Whether the Cardholder has approved or declined the issued Challenge extra_headers: Send extra headers @@ -169,16 +173,20 @@ async def challenge_response( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> None: - """ - Card program's response to a 3DS Challenge Request (CReq) + """Card program's response to a 3DS Challenge Request. + + Challenge Request is emitted + as a webhook + [three_ds_authentication.challenge](https://docs.lithic.com/reference/post_three-ds-authentication-challenge) + and your Card Program needs to be configured with Out of Band (OOB) Challenges + in order to receive it (see https://docs.lithic.com/docs/3ds-challenge-flow for + more information). Args: - token: Globally unique identifier for the 3DS authentication. This token is sent as - part of the initial 3DS Decisioning Request and as part of the 3DS Challenge - Event in the [ThreeDSAuthentication](#/components/schemas/ThreeDSAuthentication) - object + token: Globally unique identifier for 3DS Authentication that resulted in + PENDING_CHALLENGE authentication result. - challenge_response: Whether the Cardholder has Approved or Declined the issued Challenge + challenge_response: Whether the Cardholder has approved or declined the issued Challenge extra_headers: Send extra headers diff --git a/src/lithic/types/auth_rules/__init__.py b/src/lithic/types/auth_rules/__init__.py index b2982d4a..cb697fd1 100644 --- a/src/lithic/types/auth_rules/__init__.py +++ b/src/lithic/types/auth_rules/__init__.py @@ -2,6 +2,7 @@ from __future__ import annotations +from .rule_stats import RuleStats as RuleStats from .v2_list_params import V2ListParams as V2ListParams from .v2_apply_params import V2ApplyParams as V2ApplyParams from .v2_draft_params import V2DraftParams as V2DraftParams @@ -19,6 +20,8 @@ from .conditional_attribute import ConditionalAttribute as ConditionalAttribute from .velocity_limit_params import VelocityLimitParams as VelocityLimitParams from .auth_rule_condition_param import AuthRuleConditionParam as AuthRuleConditionParam +from .v2_retrieve_report_params import V2RetrieveReportParams as V2RetrieveReportParams +from .v2_retrieve_report_response import V2RetrieveReportResponse as V2RetrieveReportResponse from .velocity_limit_params_param import VelocityLimitParamsParam as VelocityLimitParamsParam from .conditional_block_parameters import ConditionalBlockParameters as ConditionalBlockParameters from .conditional_block_parameters_param import ConditionalBlockParametersParam as ConditionalBlockParametersParam diff --git a/src/lithic/types/auth_rules/rule_stats.py b/src/lithic/types/auth_rules/rule_stats.py new file mode 100644 index 00000000..b3e621f9 --- /dev/null +++ b/src/lithic/types/auth_rules/rule_stats.py @@ -0,0 +1,56 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["RuleStats", "Example"] + + +class Example(BaseModel): + approved: Optional[bool] = None + """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 event token.""" + + timestamp: Optional[datetime] = None + """The timestamp of the event.""" + + +class RuleStats(BaseModel): + approved: Optional[int] = None + """ + The total number of historical transactions approved by this rule during the + 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 + relevant period, or the number of transactions that would have been declined if + the rule was evaluated in shadow mode. + """ + + examples: Optional[List[Example]] = None + """Example events and their outcomes.""" + + version: Optional[int] = None + """ + The version of the rule, this is incremented whenever the rule's parameters + change. + """ diff --git a/src/lithic/types/auth_rules/v2/backtest_results.py b/src/lithic/types/auth_rules/v2/backtest_results.py index 7d5e223f..5496ba32 100644 --- a/src/lithic/types/auth_rules/v2/backtest_results.py +++ b/src/lithic/types/auth_rules/v2/backtest_results.py @@ -1,120 +1,18 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional +from typing import Optional from datetime import datetime -from typing_extensions import Literal from ...._models import BaseModel +from ..rule_stats import RuleStats -__all__ = [ - "BacktestResults", - "Results", - "ResultsCurrentVersion", - "ResultsCurrentVersionExample", - "ResultsDraftVersion", - "ResultsDraftVersionExample", - "SimulationParameters", -] - - -class ResultsCurrentVersionExample(BaseModel): - approved: Optional[bool] = None - """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 event token.""" - - timestamp: Optional[datetime] = None - """The timestamp of the event.""" - - -class ResultsCurrentVersion(BaseModel): - approved: Optional[int] = None - """ - The total number of historical transactions approved by this rule during the - 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 - 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 events and their outcomes.""" - - version: Optional[int] = None - """ - The version of the rule, this is incremented whenever the rule's parameters - change. - """ - - -class ResultsDraftVersionExample(BaseModel): - approved: Optional[bool] = None - """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 event token.""" - - timestamp: Optional[datetime] = None - """The timestamp of the event.""" - - -class ResultsDraftVersion(BaseModel): - approved: Optional[int] = None - """ - The total number of historical transactions approved by this rule during the - 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 - 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 events and their outcomes.""" - - version: Optional[int] = None - """ - The version of the rule, this is incremented whenever the rule's parameters - change. - """ +__all__ = ["BacktestResults", "Results", "SimulationParameters"] class Results(BaseModel): - current_version: Optional[ResultsCurrentVersion] = None + current_version: Optional[RuleStats] = None - draft_version: Optional[ResultsDraftVersion] = None + draft_version: Optional[RuleStats] = None class SimulationParameters(BaseModel): diff --git a/src/lithic/types/auth_rules/v2_retrieve_report_params.py b/src/lithic/types/auth_rules/v2_retrieve_report_params.py new file mode 100644 index 00000000..79d6b615 --- /dev/null +++ b/src/lithic/types/auth_rules/v2_retrieve_report_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import date +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["V2RetrieveReportParams"] + + +class V2RetrieveReportParams(TypedDict, total=False): + begin: Required[Annotated[Union[str, date], PropertyInfo(format="iso8601")]] + """Start date for the report""" + + end: Required[Annotated[Union[str, date], PropertyInfo(format="iso8601")]] + """End date for the report""" diff --git a/src/lithic/types/auth_rules/v2_retrieve_report_response.py b/src/lithic/types/auth_rules/v2_retrieve_report_response.py new file mode 100644 index 00000000..27169af6 --- /dev/null +++ b/src/lithic/types/auth_rules/v2_retrieve_report_response.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import datetime +from typing import List, Optional + +from ..._models import BaseModel +from .rule_stats import RuleStats + +__all__ = ["V2RetrieveReportResponse", "DailyStatistic"] + + +class DailyStatistic(BaseModel): + current_version_statistics: Optional[RuleStats] = None + """Detailed statistics for the current version of the rule.""" + + date: datetime.date + """The date (UTC) for which the statistics are reported.""" + + draft_version_statistics: Optional[RuleStats] = None + """Detailed statistics for the draft version of the rule.""" + + +class V2RetrieveReportResponse(BaseModel): + auth_rule_token: str + """Auth Rule Token""" + + begin: datetime.date + """The start date (UTC) of the report.""" + + daily_statistics: List[DailyStatistic] + """Daily evaluation statistics for the Auth Rule.""" + + end: datetime.date + """The end date (UTC) of the report.""" diff --git a/src/lithic/types/card_convert_physical_params.py b/src/lithic/types/card_convert_physical_params.py index 745c0426..879679cf 100644 --- a/src/lithic/types/card_convert_physical_params.py +++ b/src/lithic/types/card_convert_physical_params.py @@ -35,8 +35,10 @@ class CardConvertPhysicalParams(TypedDict, total=False): - `STANDARD_WITH_TRACKING` - USPS regular mail or similar international option, with tracking - `PRIORITY` - USPS Priority, 1-3 day shipping, with tracking - - `EXPRESS` - FedEx Express, 3-day shipping, with tracking - - `2_DAY` - FedEx 2-day shipping, with tracking - - `EXPEDITED` - FedEx Standard Overnight or similar international option, with + - `EXPRESS` - FedEx or UPS depending on card manufacturer, Express, 3-day + shipping, with tracking + - `2_DAY` - FedEx or UPS depending on card manufacturer, 2-day shipping, with tracking + - `EXPEDITED` - FedEx or UPS depending on card manufacturer, Standard Overnight + or similar international option, with tracking """ diff --git a/src/lithic/types/card_create_params.py b/src/lithic/types/card_create_params.py index fb295a5b..3318f48e 100644 --- a/src/lithic/types/card_create_params.py +++ b/src/lithic/types/card_create_params.py @@ -121,10 +121,12 @@ class CardCreateParams(TypedDict, total=False): - `STANDARD_WITH_TRACKING` - USPS regular mail or similar international option, with tracking - `PRIORITY` - USPS Priority, 1-3 day shipping, with tracking - - `EXPRESS` - FedEx Express, 3-day shipping, with tracking - - `2_DAY` - FedEx 2-day shipping, with tracking - - `EXPEDITED` - FedEx Standard Overnight or similar international option, with + - `EXPRESS` - FedEx or UPS depending on card manufacturer, Express, 3-day + shipping, with tracking + - `2_DAY` - FedEx or UPS depending on card manufacturer, 2-day shipping, with tracking + - `EXPEDITED` - FedEx or UPS depending on card manufacturer, Standard Overnight + or similar international option, with tracking """ spend_limit: int diff --git a/src/lithic/types/card_reissue_params.py b/src/lithic/types/card_reissue_params.py index ca25add9..2067ba9c 100644 --- a/src/lithic/types/card_reissue_params.py +++ b/src/lithic/types/card_reissue_params.py @@ -35,8 +35,10 @@ class CardReissueParams(TypedDict, total=False): - `STANDARD_WITH_TRACKING` - USPS regular mail or similar international option, with tracking - `PRIORITY` - USPS Priority, 1-3 day shipping, with tracking - - `EXPRESS` - FedEx Express, 3-day shipping, with tracking - - `2_DAY` - FedEx 2-day shipping, with tracking - - `EXPEDITED` - FedEx Standard Overnight or similar international option, with + - `EXPRESS` - FedEx or UPS depending on card manufacturer, Express, 3-day + shipping, with tracking + - `2_DAY` - FedEx or UPS depending on card manufacturer, 2-day shipping, with tracking + - `EXPEDITED` - FedEx or UPS depending on card manufacturer, Standard Overnight + or similar international option, with tracking """ diff --git a/src/lithic/types/card_renew_params.py b/src/lithic/types/card_renew_params.py index 832b2ca6..9c832103 100644 --- a/src/lithic/types/card_renew_params.py +++ b/src/lithic/types/card_renew_params.py @@ -49,8 +49,10 @@ class CardRenewParams(TypedDict, total=False): - `STANDARD_WITH_TRACKING` - USPS regular mail or similar international option, with tracking - `PRIORITY` - USPS Priority, 1-3 day shipping, with tracking - - `EXPRESS` - FedEx Express, 3-day shipping, with tracking - - `2_DAY` - FedEx 2-day shipping, with tracking - - `EXPEDITED` - FedEx Standard Overnight or similar international option, with + - `EXPRESS` - FedEx or UPS depending on card manufacturer, Express, 3-day + shipping, with tracking + - `2_DAY` - FedEx or UPS depending on card manufacturer, 2-day shipping, with tracking + - `EXPEDITED` - FedEx or UPS depending on card manufacturer, Standard Overnight + or similar international option, with tracking """ diff --git a/src/lithic/types/external_bank_account_create_params.py b/src/lithic/types/external_bank_account_create_params.py index 441ce050..10cefa11 100644 --- a/src/lithic/types/external_bank_account_create_params.py +++ b/src/lithic/types/external_bank_account_create_params.py @@ -16,6 +16,7 @@ "BankVerifiedCreateBankAccountAPIRequest", "PlaidCreateBankAccountAPIRequest", "ExternallyVerifiedCreateBankAccountAPIRequest", + "UnverifiedCreateBankAccountAPIRequest", ] @@ -177,8 +178,66 @@ class ExternallyVerifiedCreateBankAccountAPIRequest(TypedDict, total=False): """User Defined ID""" +class UnverifiedCreateBankAccountAPIRequest(TypedDict, total=False): + account_number: Required[str] + """Account Number""" + + country: Required[str] + """The country that the bank account is located in using ISO 3166-1. + + We will only accept USA bank accounts e.g., USA + """ + + currency: Required[str] + """currency of the external account 3-character alphabetic ISO 4217 code""" + + owner: Required[str] + """Legal Name of the business or individual who owns the external account. + + This will appear in statements + """ + + owner_type: Required[OwnerType] + """Owner Type""" + + routing_number: Required[str] + """Routing Number""" + + type: Required[Literal["CHECKING", "SAVINGS"]] + """Account Type""" + + verification_method: Required[Literal["UNVERIFIED"]] + """Verification Method""" + + account_token: str + """Indicates which Lithic account the external account is associated with. + + For external accounts that are associated with the program, account_token field + returned will be null + """ + + address: ExternalBankAccountAddressParam + """Address""" + + company_id: str + """Optional field that helps identify bank accounts in receipts""" + + dob: Annotated[Union[str, date], PropertyInfo(format="iso8601")] + """Date of Birth of the Individual that owns the external bank account""" + + doing_business_as: str + """Doing Business As""" + + name: str + """The nickname for this External Bank Account""" + + user_defined_id: str + """User Defined ID""" + + ExternalBankAccountCreateParams: TypeAlias = Union[ BankVerifiedCreateBankAccountAPIRequest, PlaidCreateBankAccountAPIRequest, ExternallyVerifiedCreateBankAccountAPIRequest, + UnverifiedCreateBankAccountAPIRequest, ] diff --git a/src/lithic/types/financial_accounts/statements/statement_line_items.py b/src/lithic/types/financial_accounts/statements/statement_line_items.py index 069b1881..7e5e4c38 100644 --- a/src/lithic/types/financial_accounts/statements/statement_line_items.py +++ b/src/lithic/types/financial_accounts/statements/statement_line_items.py @@ -67,6 +67,7 @@ class Data(BaseModel): "CASH_BACK", "CASH_BACK_REVERSAL", "CLEARING", + "COLLECTION", "CORRECTION_CREDIT", "CORRECTION_DEBIT", "CREDIT_AUTHORIZATION", diff --git a/src/lithic/types/financial_transaction.py b/src/lithic/types/financial_transaction.py index 0865928d..07249cb9 100644 --- a/src/lithic/types/financial_transaction.py +++ b/src/lithic/types/financial_transaction.py @@ -52,6 +52,7 @@ class Event(BaseModel): "CASH_BACK", "CASH_BACK_REVERSAL", "CLEARING", + "COLLECTION", "CORRECTION_CREDIT", "CORRECTION_DEBIT", "CREDIT_AUTHORIZATION", diff --git a/src/lithic/types/fraud/__init__.py b/src/lithic/types/fraud/__init__.py new file mode 100644 index 00000000..17325491 --- /dev/null +++ b/src/lithic/types/fraud/__init__.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .transaction_report_params import TransactionReportParams as TransactionReportParams +from .transaction_report_response import TransactionReportResponse as TransactionReportResponse +from .transaction_retrieve_response import TransactionRetrieveResponse as TransactionRetrieveResponse diff --git a/src/lithic/types/fraud/transaction_report_params.py b/src/lithic/types/fraud/transaction_report_params.py new file mode 100644 index 00000000..997d066e --- /dev/null +++ b/src/lithic/types/fraud/transaction_report_params.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["TransactionReportParams"] + + +class TransactionReportParams(TypedDict, total=False): + fraud_status: Required[Literal["SUSPECTED_FRAUD", "FRAUDULENT", "NOT_FRAUDULENT"]] + """ + The fraud status of the transaction, string (enum) supporting the following + values: + + - `SUSPECTED_FRAUD`: The transaction is suspected to be fraudulent, but this + hasn’t been confirmed. + - `FRAUDULENT`: The transaction is confirmed to be fraudulent. A transaction may + immediately be moved into this state, or be graduated into this state from the + `SUSPECTED_FRAUD` state. + - `NOT_FRAUDULENT`: The transaction is (explicitly) marked as not fraudulent. A + transaction may immediately be moved into this state, or be graduated into + this state from the `SUSPECTED_FRAUD` state. + """ + + comment: str + """ + Optional field providing additional information or context about why the + transaction is considered fraudulent. + """ + + fraud_type: Literal[ + "FIRST_PARTY_FRAUD", "ACCOUNT_TAKEOVER", "CARD_COMPROMISED", "IDENTITY_THEFT", "CARDHOLDER_MANIPULATION" + ] + """ + Specifies the type or category of fraud that the transaction is suspected or + confirmed to involve, string (enum) supporting the following values: + + - `FIRST_PARTY_FRAUD`: First-party fraud occurs when a legitimate account or + cardholder intentionally misuses financial services for personal gain. This + includes actions such as disputing legitimate transactions to obtain a refund, + abusing return policies, or defaulting on credit obligations without intent to + repay. + - `ACCOUNT_TAKEOVER`: Account takeover fraud occurs when a fraudster gains + unauthorized access to an existing account, modifies account settings, and + carries out fraudulent transactions. + - `CARD_COMPROMISED`: Card compromised fraud occurs when a fraudster gains + access to card details without taking over the account, such as through + physical card theft, cloning, or online data breaches. + - `IDENTITY_THEFT`: Identity theft fraud occurs when a fraudster uses stolen + personal information, such as Social Security numbers or addresses, to open + accounts, apply for loans, or conduct financial transactions in someone's + name. + - `CARDHOLDER_MANIPULATION`: This type of fraud occurs when a fraudster + manipulates or coerces a legitimate cardholder into unauthorized transactions, + often through social engineering tactics. + """ diff --git a/src/lithic/types/fraud/transaction_report_response.py b/src/lithic/types/fraud/transaction_report_response.py new file mode 100644 index 00000000..e0ec20f2 --- /dev/null +++ b/src/lithic/types/fraud/transaction_report_response.py @@ -0,0 +1,73 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["TransactionReportResponse"] + + +class TransactionReportResponse(BaseModel): + fraud_status: Literal["SUSPECTED_FRAUD", "FRAUDULENT", "NOT_FRAUDULENT", "NO_REPORTED_FRAUD"] + """ + The fraud status of the transaction, string (enum) supporting the following + values: + + - `SUSPECTED_FRAUD`: The transaction is suspected to be fraudulent, but this + hasn’t been confirmed. + - `FRAUDULENT`: The transaction is confirmed to be fraudulent. A transaction may + immediately be moved into this state, or be graduated into this state from the + `SUSPECTED_FRAUD` state. + - `NOT_FRAUDULENT`: The transaction is (explicitly) marked as not fraudulent. A + transaction may immediately be moved into this state, or be graduated into + this state from the `SUSPECTED_FRAUD` state. + - `NO_REPORTED_FRAUD`: Indicates that no fraud report exists for the + transaction. It is the default state for transactions that have not been + analyzed or associated with any known fraudulent activity. + """ + + transaction_token: str + """ + The universally unique identifier (UUID) associated with the transaction being + reported. + """ + + comment: Optional[str] = None + """Provides additional context or details about the fraud report.""" + + created_at: Optional[datetime] = None + """Timestamp representing when the fraud report was created.""" + + fraud_type: Optional[ + Literal[ + "FIRST_PARTY_FRAUD", "ACCOUNT_TAKEOVER", "CARD_COMPROMISED", "IDENTITY_THEFT", "CARDHOLDER_MANIPULATION" + ] + ] = None + """ + Specifies the type or category of fraud that the transaction is suspected or + confirmed to involve, string (enum) supporting the following values: + + - `FIRST_PARTY_FRAUD`: First-party fraud occurs when a legitimate account or + cardholder intentionally misuses financial services for personal gain. This + includes actions such as disputing legitimate transactions to obtain a refund, + abusing return policies, or defaulting on credit obligations without intent to + repay. + - `ACCOUNT_TAKEOVER`: Account takeover fraud occurs when a fraudster gains + unauthorized access to an existing account, modifies account settings, and + carries out fraudulent transactions. + - `CARD_COMPROMISED`: Card compromised fraud occurs when a fraudster gains + access to card details without taking over the account, such as through + physical card theft, cloning, or online data breaches. + - `IDENTITY_THEFT`: Identity theft fraud occurs when a fraudster uses stolen + personal information, such as Social Security numbers or addresses, to open + accounts, apply for loans, or conduct financial transactions in someone's + name. + - `CARDHOLDER_MANIPULATION`: This type of fraud occurs when a fraudster + manipulates or coerces a legitimate cardholder into unauthorized transactions, + often through social engineering tactics. + """ + + updated_at: Optional[datetime] = None + """Timestamp representing the last update to the fraud report.""" diff --git a/src/lithic/types/fraud/transaction_retrieve_response.py b/src/lithic/types/fraud/transaction_retrieve_response.py new file mode 100644 index 00000000..9e740279 --- /dev/null +++ b/src/lithic/types/fraud/transaction_retrieve_response.py @@ -0,0 +1,73 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["TransactionRetrieveResponse"] + + +class TransactionRetrieveResponse(BaseModel): + fraud_status: Literal["SUSPECTED_FRAUD", "FRAUDULENT", "NOT_FRAUDULENT", "NO_REPORTED_FRAUD"] + """ + The fraud status of the transaction, string (enum) supporting the following + values: + + - `SUSPECTED_FRAUD`: The transaction is suspected to be fraudulent, but this + hasn’t been confirmed. + - `FRAUDULENT`: The transaction is confirmed to be fraudulent. A transaction may + immediately be moved into this state, or be graduated into this state from the + `SUSPECTED_FRAUD` state. + - `NOT_FRAUDULENT`: The transaction is (explicitly) marked as not fraudulent. A + transaction may immediately be moved into this state, or be graduated into + this state from the `SUSPECTED_FRAUD` state. + - `NO_REPORTED_FRAUD`: Indicates that no fraud report exists for the + transaction. It is the default state for transactions that have not been + analyzed or associated with any known fraudulent activity. + """ + + transaction_token: str + """ + The universally unique identifier (UUID) associated with the transaction being + reported. + """ + + comment: Optional[str] = None + """Provides additional context or details about the fraud report.""" + + created_at: Optional[datetime] = None + """Timestamp representing when the fraud report was created.""" + + fraud_type: Optional[ + Literal[ + "FIRST_PARTY_FRAUD", "ACCOUNT_TAKEOVER", "CARD_COMPROMISED", "IDENTITY_THEFT", "CARDHOLDER_MANIPULATION" + ] + ] = None + """ + Specifies the type or category of fraud that the transaction is suspected or + confirmed to involve, string (enum) supporting the following values: + + - `FIRST_PARTY_FRAUD`: First-party fraud occurs when a legitimate account or + cardholder intentionally misuses financial services for personal gain. This + includes actions such as disputing legitimate transactions to obtain a refund, + abusing return policies, or defaulting on credit obligations without intent to + repay. + - `ACCOUNT_TAKEOVER`: Account takeover fraud occurs when a fraudster gains + unauthorized access to an existing account, modifies account settings, and + carries out fraudulent transactions. + - `CARD_COMPROMISED`: Card compromised fraud occurs when a fraudster gains + access to card details without taking over the account, such as through + physical card theft, cloning, or online data breaches. + - `IDENTITY_THEFT`: Identity theft fraud occurs when a fraudster uses stolen + personal information, such as Social Security numbers or addresses, to open + accounts, apply for loans, or conduct financial transactions in someone's + name. + - `CARDHOLDER_MANIPULATION`: This type of fraud occurs when a fraudster + manipulates or coerces a legitimate cardholder into unauthorized transactions, + often through social engineering tactics. + """ + + updated_at: Optional[datetime] = None + """Timestamp representing the last update to the fraud report.""" diff --git a/src/lithic/types/non_pci_card.py b/src/lithic/types/non_pci_card.py index cdaf8d6e..8175e27d 100644 --- a/src/lithic/types/non_pci_card.py +++ b/src/lithic/types/non_pci_card.py @@ -5,6 +5,7 @@ from typing_extensions import Literal from .._models import BaseModel +from .spend_limit_duration import SpendLimitDuration __all__ = ["NonPCICard", "Funding"] @@ -79,8 +80,20 @@ class NonPCICard(BaseModel): be declined. """ - spend_limit_duration: Literal["ANNUALLY", "FOREVER", "MONTHLY", "TRANSACTION", "DAILY"] - """Spend limit duration""" + spend_limit_duration: SpendLimitDuration + """Spend limit duration values: + + - `ANNUALLY` - Card will authorize transactions up to spend limit for the + trailing year. + - `FOREVER` - Card will authorize only up to spend limit for the entire lifetime + of the card. + - `MONTHLY` - Card will authorize transactions up to spend limit for the + trailing month. To support recurring monthly payments, which can occur on + different day every month, the time window we consider for monthly velocity + starts 6 days after the current calendar date one month prior. + - `TRANSACTION` - Card will authorize multiple transactions if each individual + transaction is under the spend limit. + """ state: Literal["CLOSED", "OPEN", "PAUSED", "PENDING_ACTIVATION", "PENDING_FULFILLMENT"] """Card state values: \\** `CLOSED` - Card will no longer approve authorizations. diff --git a/src/lithic/types/payment.py b/src/lithic/types/payment.py index 37171345..644537e5 100644 --- a/src/lithic/types/payment.py +++ b/src/lithic/types/payment.py @@ -91,6 +91,8 @@ class MethodAttributes(BaseModel): trace_numbers: List[Optional[str]] + addenda: Optional[str] = None + class Payment(BaseModel): token: str diff --git a/src/lithic/types/payment_create_params.py b/src/lithic/types/payment_create_params.py index 97e65835..33bd7c7f 100644 --- a/src/lithic/types/payment_create_params.py +++ b/src/lithic/types/payment_create_params.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Optional from typing_extensions import Literal, Required, TypedDict __all__ = ["PaymentCreateParams", "MethodAttributes"] @@ -33,3 +34,5 @@ class PaymentCreateParams(TypedDict, total=False): class MethodAttributes(TypedDict, total=False): sec_code: Required[Literal["CCD", "PPD", "WEB"]] + + addenda: Optional[str] diff --git a/src/lithic/types/three_ds/authentication_retrieve_response.py b/src/lithic/types/three_ds/authentication_retrieve_response.py index 6662cafd..98e22a19 100644 --- a/src/lithic/types/three_ds/authentication_retrieve_response.py +++ b/src/lithic/types/three_ds/authentication_retrieve_response.py @@ -73,7 +73,7 @@ class Cardholder(BaseModel): Indicates whether the shipping address and billing address provided by the cardholder are the same. This value - and assessment of whether the addresses match - is provided directly in the 3DS request and is not determined by Lithic. - Maps to EMV 3DS field addrMatch. + Maps to EMV 3DS field `addrMatch`. """ billing_address: Optional[CardholderBillingAddress] = None @@ -82,28 +82,28 @@ class Cardholder(BaseModel): email: Optional[str] = None """ Email address that is either provided by the cardholder or is on file with the - merchant in a 3RI request. Maps to EMV 3DS field email. + merchant in a 3RI request. Maps to EMV 3DS field `email`. """ name: Optional[str] = None - """Name of the cardholder. Maps to EMV 3DS field cardholderName.""" + """Name of the cardholder. Maps to EMV 3DS field `cardholderName`.""" phone_number_home: Optional[str] = None """Home phone number provided by the cardholder. - Maps to EMV 3DS fields homePhone.cc and homePhone.subscriber. + Maps to EMV 3DS fields `homePhone.cc` and `homePhone.subscriber`. """ phone_number_mobile: Optional[str] = None """Mobile/cell phone number provided by the cardholder. - Maps to EMV 3DS fields mobilePhone.cc and mobilePhone.subscriber. + Maps to EMV 3DS fields `mobilePhone.cc` and `mobilePhone.subscriber`. """ phone_number_work: Optional[str] = None """Work phone number provided by the cardholder. - Maps to EMV 3DS fields workPhone.cc and workPhone.subscriber. + Maps to EMV 3DS fields `workPhone.cc` and `workPhone.subscriber`. """ shipping_address: Optional[CardholderShippingAddress] = None @@ -114,7 +114,7 @@ class MerchantRiskIndicator(BaseModel): delivery_email_address: Optional[str] = None """ In transactions with electronic delivery, email address to which merchandise is - delivered. Maps to EMV 3DS field deliveryEmailAddress. + delivered. Maps to EMV 3DS field `deliveryEmailAddress`. """ delivery_time_frame: Optional[ @@ -122,44 +122,46 @@ class MerchantRiskIndicator(BaseModel): ] = None """The delivery time frame for the merchandise. - Maps to EMV 3DS field deliveryTimeframe. + Maps to EMV 3DS field `deliveryTimeframe`. """ gift_card_amount: Optional[int] = None """ In prepaid or gift card purchase transactions, purchase amount total in major units (e.g., a purchase of USD $205.10 would be 205). Maps to EMV 3DS field - giftCardAmount. + `giftCardAmount`. """ gift_card_count: Optional[int] = None """ In prepaid or gift card purchase transactions, count of individual prepaid or - gift cards/codes purchased. Maps to EMV 3DS field giftCardCount. + gift cards/codes purchased. Maps to EMV 3DS field `giftCardCount`. """ gift_card_currency: Optional[str] = None """In prepaid or gift card purchase transactions, currency code of the gift card. - Maps to EMV 3DS field giftCardCurr. + Maps to EMV 3DS field `giftCardCurr`. Permitted values: ISO 4217 three-character + currency code (e.g., USD). """ order_availability: Optional[Literal["FUTURE_AVAILABILITY", "MERCHANDISE_AVAILABLE"]] = None """ Indicates whether the purchase is for merchandise that is available now or at a - future date. Maps to EMV 3DS field preOrderPurchaseInd. + future date. Maps to EMV 3DS field `preOrderPurchaseInd`. """ pre_order_available_date: Optional[datetime] = None """ In pre-order purchase transactions, the expected date that the merchandise will - be available. Maps to EMV 3DS field preOrderDate. + be available. Maps to EMV 3DS field `preOrderDate`. Permitted values: Date + string in the ISO 8601 format yyyy-MM-dd'T'hh:mm:ssZ """ reorder_items: Optional[Literal["FIRST_TIME_ORDERED", "REORDERED"]] = None """Indicates whether the cardholder is reordering previously purchased merchandise. - Maps to EMV 3DS field reorderItemsInd. + Maps to EMV 3DS field `reorderItemsInd`. """ shipping_method: Optional[ @@ -179,7 +181,8 @@ class MerchantRiskIndicator(BaseModel): If purchase includes one or more item, this indicator is used for the physical goods; if the purchase only includes digital goods, this indicator is used to - describe the most expensive item purchased. Maps to EMV 3DS field shipIndicator. + describe the most expensive item purchased. Maps to EMV 3DS field + `shipIndicator`. """ @@ -187,23 +190,24 @@ class Merchant(BaseModel): id: str """Merchant identifier as assigned by the acquirer. - Maps to EMV 3DS field acquirerMerchantId. + Maps to EMV 3DS field `acquirerMerchantId`. """ country: str """Country code of the merchant requesting 3DS authentication. - Maps to EMV 3DS field merchantCountryCode. + Maps to EMV 3DS field `merchantCountryCode`. Permitted values: ISO 3166-1 + alpha-3 country code (e.g., USA). """ mcc: str """ Merchant category code assigned to the merchant that describes its business - activity type. Maps to EMV 3DS field mcc. + activity type. Maps to EMV 3DS field `mcc`. """ name: str - """Name of the merchant. Maps to EMV 3DS field merchantName.""" + """Name of the merchant. Maps to EMV 3DS field `merchantName`.""" risk_indicator: MerchantRiskIndicator """ @@ -222,7 +226,8 @@ class AdditionalData(BaseModel): network_risk_score: Optional[int] = None """ Mastercard only: Assessment by the network of the authentication risk level, - with a higher value indicating a higher amount of risk. + with a higher value indicating a higher amount of risk. Permitted values: + Integer between 0-950, in increments of 50. """ @@ -230,51 +235,60 @@ class App(BaseModel): device_info: Optional[str] = None """ Device information gathered from the cardholder's device - JSON name/value pairs - that is Base64url encoded. Maps to EMV 3DS field deviceInfo. + that is Base64url encoded. Maps to EMV 3DS field `deviceInfo`. """ ip: Optional[str] = None """External IP address used by the app generating the 3DS authentication request. - Maps to EMV 3DS field appIp. + Maps to EMV 3DS field `appIp`. """ class Browser(BaseModel): + accept_header: Optional[str] = None + """ + Content of the HTTP accept headers as sent from the cardholder's browser to the + 3DS requestor (e.g., merchant or digital wallet). + """ + ip: Optional[str] = None """ IP address of the browser as returned by the HTTP headers to the 3DS requestor - (e.g., merchant or digital wallet). Maps to EMV 3DS field browserIP. + (e.g., merchant or digital wallet). Maps to EMV 3DS field `browserIP`. """ java_enabled: Optional[bool] = None """Indicates whether the cardholder's browser has the ability to execute Java. - Maps to EMV 3DS field browserJavaEnabled. + Maps to EMV 3DS field `browserJavaEnabled`. """ javascript_enabled: Optional[bool] = None """Indicates whether the cardholder's browser has the ability to execute JavaScript. - Maps to EMV 3DS field browserJavascriptEnabled. + Maps to EMV 3DS field `browserJavascriptEnabled`. """ language: Optional[str] = None """Language of the cardholder's browser as defined in IETF BCP47. - Maps to EMV 3DS field browserLanguage. + Maps to EMV 3DS field `browserLanguage`. """ time_zone: Optional[str] = None """ Time zone of the cardholder's browser offset in minutes between UTC and the cardholder browser's local time. The offset is positive if the local time is - behind UTC and negative if it is ahead. Maps to EMV 3DS field browserTz. + behind UTC and negative if it is ahead. Maps to EMV 3DS field `browserTz`. """ user_agent: Optional[str] = None - """Content of the HTTP user-agent header. Maps to EMV 3DS field browserUserAgent.""" + """Content of the HTTP user-agent header. + + Maps to EMV 3DS field `browserUserAgent`. + """ class ChallengeMetadata(BaseModel): @@ -289,7 +303,7 @@ class Transaction(BaseModel): amount: float """Amount of the purchase in minor units of currency with all punctuation removed. - Maps to EMV 3DS field purchaseAmount. + Maps to EMV 3DS field `purchaseAmount`. """ cardholder_amount: Optional[float] = None @@ -299,18 +313,23 @@ class Transaction(BaseModel): """ currency: str - """Currency of the purchase. Maps to EMV 3DS field purchaseCurrency.""" + """Currency of the purchase. + + Maps to EMV 3DS field `purchaseCurrency`. Permitted values: ISO 4217 + three-character currency code (e.g., USD). + """ currency_exponent: float """Minor units of currency, as specified in ISO 4217 currency exponent. - Maps to EMV 3DS field purchaseExponent. + Maps to EMV 3DS field `purchaseExponent`. """ date_time: datetime """ Date and time when the authentication was generated by the merchant/acquirer's - 3DS server. Maps to EMV 3DS field purchaseDate. + 3DS server. Maps to EMV 3DS field `purchaseDate`. Permitted values: Date string + in the ISO 8601 format yyyy-MM-dd'T'hh:mm:ssZ. """ type: Optional[ @@ -324,13 +343,16 @@ class Transaction(BaseModel): ] = None """Type of the transaction for which a 3DS authentication request is occurring. - Maps to EMV 3DS field transType. + Maps to EMV 3DS field `transType`. """ class AuthenticationRetrieveResponse(BaseModel): token: str - """Globally unique identifier for the 3DS authentication.""" + """Globally unique identifier for the 3DS authentication. + + Permitted values: 36-digit version 4 UUID (including hyphens). + """ account_type: Optional[Literal["CREDIT", "DEBIT", "NOT_APPLICABLE"]] = None """Type of account/card that is being used for the transaction. @@ -350,7 +372,7 @@ class AuthenticationRetrieveResponse(BaseModel): card_token: str """ Globally unique identifier for the card on which the 3DS authentication has - occurred. + occurred. Permitted values: 36-digit version 4 UUID (including hyphens). """ cardholder: Cardholder @@ -359,11 +381,14 @@ class AuthenticationRetrieveResponse(BaseModel): channel: Literal["APP_BASED", "BROWSER", "THREE_DS_REQUESTOR_INITIATED"] """Channel in which the authentication occurs. - Maps to EMV 3DS field deviceChannel. + Maps to EMV 3DS field `deviceChannel`. """ created: datetime - """Date and time when the authentication was created in Lithic's system.""" + """Date and time when the authentication was created in Lithic's system. + + Permitted values: Date string in the ISO 8601 format yyyy-MM-dd'T'hh:mm:ssZ. + """ merchant: Merchant """ @@ -429,7 +454,7 @@ class AuthenticationRetrieveResponse(BaseModel): """ Type of authentication request - i.e., the type of transaction or interaction is causing the merchant to request an authentication. Maps to EMV 3DS field - threeDSRequestorAuthenticationInd. + `threeDSRequestorAuthenticationInd`. """ browser: Optional[Browser] = None @@ -439,15 +464,26 @@ class AuthenticationRetrieveResponse(BaseModel): """ challenge_metadata: Optional[ChallengeMetadata] = None - """Metadata about the challenge method and delivery.""" + """Metadata about the challenge method and delivery. + + Only present when a challenge is triggered. + """ challenge_orchestrated_by: Optional[Literal["LITHIC", "CUSTOMER", "NO_CHALLENGE"]] = None - """Entity that orchestrates the challenge.""" + """Entity that orchestrates the challenge. - decision_made_by: Optional[Literal["CUSTOMER_ENDPOINT", "LITHIC_DEFAULT", "LITHIC_RULES", "NETWORK", "UNKNOWN"]] = ( - None - ) - """Entity that made the authentication decision.""" + This won't be set for authentications for which a decision has not yet been made + (e.g. in-flight customer decisioning request). + """ + + decision_made_by: Optional[ + Literal["LITHIC_RULES", "LITHIC_DEFAULT", "CUSTOMER_RULES", "CUSTOMER_ENDPOINT", "NETWORK", "UNKNOWN"] + ] = None + """Entity that made the authentication decision. + + This won't be set for authentications for which a decision has not yet been made + (e.g. in-flight customer decisioning request). + """ three_ri_request_type: Optional[ Literal[ @@ -470,11 +506,11 @@ class AuthenticationRetrieveResponse(BaseModel): ] ] = None """ - Type of 3DS Requestor Initiated (3RI) request i.e., a 3DS authentication that + Type of 3DS Requestor Initiated (3RI) request — i.e., a 3DS authentication that takes place at the initiation of the merchant rather than the cardholder. The most common example of this is where a merchant is authenticating before billing for a recurring transaction such as a pay TV subscription or a utility bill. - Maps to EMV 3DS field threeRIInd. + Maps to EMV 3DS field `threeRIInd`. """ transaction: Optional[Transaction] = None diff --git a/src/lithic/types/three_ds/authentication_simulate_params.py b/src/lithic/types/three_ds/authentication_simulate_params.py index 67030433..da9488ef 100644 --- a/src/lithic/types/three_ds/authentication_simulate_params.py +++ b/src/lithic/types/three_ds/authentication_simulate_params.py @@ -9,11 +9,13 @@ class AuthenticationSimulateParams(TypedDict, total=False): merchant: Required[Merchant] + """Merchant information for the simulated transaction""" pan: Required[str] """Sixteen digit card number.""" transaction: Required[Transaction] + """Transaction details for the simulation""" card_expiry_check: Literal["MATCH", "MISMATCH", "NOT_PRESENT"] """When set will use the following values as part of the Simulated Authentication. diff --git a/src/lithic/types/three_ds/authentication_simulate_response.py b/src/lithic/types/three_ds/authentication_simulate_response.py index 3eeeae26..2c376db6 100644 --- a/src/lithic/types/three_ds/authentication_simulate_response.py +++ b/src/lithic/types/three_ds/authentication_simulate_response.py @@ -9,7 +9,4 @@ class AuthenticationSimulateResponse(BaseModel): token: Optional[str] = None - """ - A unique token to reference this transaction with later calls to void or clear - the authorization. - """ + """Globally unique identifier for the 3DS authentication.""" diff --git a/src/lithic/types/three_ds/decisioning_challenge_response_params.py b/src/lithic/types/three_ds/decisioning_challenge_response_params.py index b68305a5..f6ba5df5 100644 --- a/src/lithic/types/three_ds/decisioning_challenge_response_params.py +++ b/src/lithic/types/three_ds/decisioning_challenge_response_params.py @@ -11,12 +11,10 @@ class DecisioningChallengeResponseParams(TypedDict, total=False): token: Required[str] - """Globally unique identifier for the 3DS authentication. - - This token is sent as part of the initial 3DS Decisioning Request and as part of - the 3DS Challenge Event in the - [ThreeDSAuthentication](#/components/schemas/ThreeDSAuthentication) object + """ + Globally unique identifier for 3DS Authentication that resulted in + PENDING_CHALLENGE authentication result. """ challenge_response: Required[ChallengeResult] - """Whether the Cardholder has Approved or Declined the issued Challenge""" + """Whether the Cardholder has approved or declined the issued Challenge""" diff --git a/tests/api_resources/auth_rules/test_v2.py b/tests/api_resources/auth_rules/test_v2.py index 00505421..92fe418a 100644 --- a/tests/api_resources/auth_rules/test_v2.py +++ b/tests/api_resources/auth_rules/test_v2.py @@ -9,6 +9,7 @@ from lithic import Lithic, AsyncLithic from tests.utils import assert_matches_type +from lithic._utils import parse_date from lithic.pagination import SyncCursorPage, AsyncCursorPage from lithic.types.auth_rules import ( V2ListResponse, @@ -19,6 +20,7 @@ V2UpdateResponse, V2PromoteResponse, V2RetrieveResponse, + V2RetrieveReportResponse, ) # pyright: reportDeprecated=false @@ -682,16 +684,19 @@ def test_path_params_promote(self, client: Lithic) -> None: @parametrize def test_method_report(self, client: Lithic) -> None: - v2 = client.auth_rules.v2.report( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) + with pytest.warns(DeprecationWarning): + v2 = client.auth_rules.v2.report( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(V2ReportResponse, v2, path=["response"]) @parametrize def test_raw_response_report(self, client: Lithic) -> None: - response = client.auth_rules.v2.with_raw_response.report( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) + with pytest.warns(DeprecationWarning): + response = client.auth_rules.v2.with_raw_response.report( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -700,22 +705,70 @@ def test_raw_response_report(self, client: Lithic) -> None: @parametrize def test_streaming_response_report(self, client: Lithic) -> None: - with client.auth_rules.v2.with_streaming_response.report( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + with pytest.warns(DeprecationWarning): + with client.auth_rules.v2.with_streaming_response.report( + "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(V2ReportResponse, v2, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_report(self, client: Lithic) -> None: + 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.report( + "", + ) + + @parametrize + def test_method_retrieve_report(self, client: Lithic) -> None: + v2 = client.auth_rules.v2.retrieve_report( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + begin=parse_date("2019-12-27"), + end=parse_date("2019-12-27"), + ) + assert_matches_type(V2RetrieveReportResponse, v2, path=["response"]) + + @parametrize + def test_raw_response_retrieve_report(self, client: Lithic) -> None: + response = client.auth_rules.v2.with_raw_response.retrieve_report( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + begin=parse_date("2019-12-27"), + end=parse_date("2019-12-27"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + v2 = response.parse() + assert_matches_type(V2RetrieveReportResponse, v2, path=["response"]) + + @parametrize + def test_streaming_response_retrieve_report(self, client: Lithic) -> None: + with client.auth_rules.v2.with_streaming_response.retrieve_report( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + begin=parse_date("2019-12-27"), + end=parse_date("2019-12-27"), ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" v2 = response.parse() - assert_matches_type(V2ReportResponse, v2, path=["response"]) + assert_matches_type(V2RetrieveReportResponse, v2, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_report(self, client: Lithic) -> None: + def test_path_params_retrieve_report(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.report( - "", + client.auth_rules.v2.with_raw_response.retrieve_report( + auth_rule_token="", + begin=parse_date("2019-12-27"), + end=parse_date("2019-12-27"), ) @@ -1377,16 +1430,19 @@ async def test_path_params_promote(self, async_client: AsyncLithic) -> None: @parametrize async def test_method_report(self, async_client: AsyncLithic) -> None: - v2 = await async_client.auth_rules.v2.report( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) + with pytest.warns(DeprecationWarning): + v2 = await async_client.auth_rules.v2.report( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(V2ReportResponse, v2, path=["response"]) @parametrize async def test_raw_response_report(self, async_client: AsyncLithic) -> None: - response = await async_client.auth_rules.v2.with_raw_response.report( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) + with pytest.warns(DeprecationWarning): + response = await async_client.auth_rules.v2.with_raw_response.report( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1395,20 +1451,68 @@ async def test_raw_response_report(self, async_client: AsyncLithic) -> None: @parametrize async def test_streaming_response_report(self, async_client: AsyncLithic) -> None: - async with async_client.auth_rules.v2.with_streaming_response.report( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + with pytest.warns(DeprecationWarning): + async with async_client.auth_rules.v2.with_streaming_response.report( + "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(V2ReportResponse, v2, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_report(self, async_client: AsyncLithic) -> None: + 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.report( + "", + ) + + @parametrize + async def test_method_retrieve_report(self, async_client: AsyncLithic) -> None: + v2 = await async_client.auth_rules.v2.retrieve_report( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + begin=parse_date("2019-12-27"), + end=parse_date("2019-12-27"), + ) + assert_matches_type(V2RetrieveReportResponse, v2, path=["response"]) + + @parametrize + async def test_raw_response_retrieve_report(self, async_client: AsyncLithic) -> None: + response = await async_client.auth_rules.v2.with_raw_response.retrieve_report( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + begin=parse_date("2019-12-27"), + end=parse_date("2019-12-27"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + v2 = response.parse() + assert_matches_type(V2RetrieveReportResponse, v2, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve_report(self, async_client: AsyncLithic) -> None: + async with async_client.auth_rules.v2.with_streaming_response.retrieve_report( + auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + begin=parse_date("2019-12-27"), + end=parse_date("2019-12-27"), ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" v2 = await response.parse() - assert_matches_type(V2ReportResponse, v2, path=["response"]) + assert_matches_type(V2RetrieveReportResponse, v2, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_report(self, async_client: AsyncLithic) -> None: + async def test_path_params_retrieve_report(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.report( - "", + await async_client.auth_rules.v2.with_raw_response.retrieve_report( + auth_rule_token="", + begin=parse_date("2019-12-27"), + end=parse_date("2019-12-27"), ) diff --git a/tests/api_resources/fraud/__init__.py b/tests/api_resources/fraud/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/fraud/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/fraud/test_transactions.py b/tests/api_resources/fraud/test_transactions.py new file mode 100644 index 00000000..6bd76dc0 --- /dev/null +++ b/tests/api_resources/fraud/test_transactions.py @@ -0,0 +1,204 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from lithic import Lithic, AsyncLithic +from tests.utils import assert_matches_type +from lithic.types.fraud import TransactionReportResponse, TransactionRetrieveResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestTransactions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: Lithic) -> None: + transaction = client.fraud.transactions.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(TransactionRetrieveResponse, transaction, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: Lithic) -> None: + response = client.fraud.transactions.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + transaction = response.parse() + assert_matches_type(TransactionRetrieveResponse, transaction, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: Lithic) -> None: + with client.fraud.transactions.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + transaction = response.parse() + assert_matches_type(TransactionRetrieveResponse, transaction, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: Lithic) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `transaction_token` but received ''"): + client.fraud.transactions.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_report(self, client: Lithic) -> None: + transaction = client.fraud.transactions.report( + transaction_token="00000000-0000-0000-0000-000000000000", + fraud_status="SUSPECTED_FRAUD", + ) + assert_matches_type(TransactionReportResponse, transaction, path=["response"]) + + @parametrize + def test_method_report_with_all_params(self, client: Lithic) -> None: + transaction = client.fraud.transactions.report( + transaction_token="00000000-0000-0000-0000-000000000000", + fraud_status="SUSPECTED_FRAUD", + comment="comment", + fraud_type="FIRST_PARTY_FRAUD", + ) + assert_matches_type(TransactionReportResponse, transaction, path=["response"]) + + @parametrize + def test_raw_response_report(self, client: Lithic) -> None: + response = client.fraud.transactions.with_raw_response.report( + transaction_token="00000000-0000-0000-0000-000000000000", + fraud_status="SUSPECTED_FRAUD", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + transaction = response.parse() + assert_matches_type(TransactionReportResponse, transaction, path=["response"]) + + @parametrize + def test_streaming_response_report(self, client: Lithic) -> None: + with client.fraud.transactions.with_streaming_response.report( + transaction_token="00000000-0000-0000-0000-000000000000", + fraud_status="SUSPECTED_FRAUD", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + transaction = response.parse() + assert_matches_type(TransactionReportResponse, transaction, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_report(self, client: Lithic) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `transaction_token` but received ''"): + client.fraud.transactions.with_raw_response.report( + transaction_token="", + fraud_status="SUSPECTED_FRAUD", + ) + + +class TestAsyncTransactions: + 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: + transaction = await async_client.fraud.transactions.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(TransactionRetrieveResponse, transaction, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncLithic) -> None: + response = await async_client.fraud.transactions.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + transaction = response.parse() + assert_matches_type(TransactionRetrieveResponse, transaction, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncLithic) -> None: + async with async_client.fraud.transactions.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + transaction = await response.parse() + assert_matches_type(TransactionRetrieveResponse, transaction, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncLithic) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `transaction_token` but received ''"): + await async_client.fraud.transactions.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_report(self, async_client: AsyncLithic) -> None: + transaction = await async_client.fraud.transactions.report( + transaction_token="00000000-0000-0000-0000-000000000000", + fraud_status="SUSPECTED_FRAUD", + ) + assert_matches_type(TransactionReportResponse, transaction, path=["response"]) + + @parametrize + async def test_method_report_with_all_params(self, async_client: AsyncLithic) -> None: + transaction = await async_client.fraud.transactions.report( + transaction_token="00000000-0000-0000-0000-000000000000", + fraud_status="SUSPECTED_FRAUD", + comment="comment", + fraud_type="FIRST_PARTY_FRAUD", + ) + assert_matches_type(TransactionReportResponse, transaction, path=["response"]) + + @parametrize + async def test_raw_response_report(self, async_client: AsyncLithic) -> None: + response = await async_client.fraud.transactions.with_raw_response.report( + transaction_token="00000000-0000-0000-0000-000000000000", + fraud_status="SUSPECTED_FRAUD", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + transaction = response.parse() + assert_matches_type(TransactionReportResponse, transaction, path=["response"]) + + @parametrize + async def test_streaming_response_report(self, async_client: AsyncLithic) -> None: + async with async_client.fraud.transactions.with_streaming_response.report( + transaction_token="00000000-0000-0000-0000-000000000000", + fraud_status="SUSPECTED_FRAUD", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + transaction = await response.parse() + assert_matches_type(TransactionReportResponse, transaction, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_report(self, async_client: AsyncLithic) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `transaction_token` but received ''"): + await async_client.fraud.transactions.with_raw_response.report( + transaction_token="", + fraud_status="SUSPECTED_FRAUD", + ) diff --git a/tests/api_resources/test_external_bank_accounts.py b/tests/api_resources/test_external_bank_accounts.py index 172ab15a..0d2a7650 100644 --- a/tests/api_resources/test_external_bank_accounts.py +++ b/tests/api_resources/test_external_bank_accounts.py @@ -246,6 +246,86 @@ def test_streaming_response_create_overload_3(self, client: Lithic) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_create_overload_4(self, client: Lithic) -> None: + external_bank_account = client.external_bank_accounts.create( + account_number="12345678901234567", + country="USD", + currency="USD", + owner="owner", + owner_type="INDIVIDUAL", + routing_number="123456789", + type="CHECKING", + verification_method="UNVERIFIED", + ) + assert_matches_type(ExternalBankAccountCreateResponse, external_bank_account, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_4(self, client: Lithic) -> None: + external_bank_account = client.external_bank_accounts.create( + account_number="12345678901234567", + country="USD", + currency="USD", + owner="owner", + owner_type="INDIVIDUAL", + routing_number="123456789", + type="CHECKING", + verification_method="UNVERIFIED", + account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + address={ + "address1": "x", + "city": "x", + "country": "USD", + "postal_code": "11201", + "state": "xx", + "address2": "x", + }, + company_id="sq", + dob=parse_date("2019-12-27"), + doing_business_as="x", + name="name", + user_defined_id="x", + ) + assert_matches_type(ExternalBankAccountCreateResponse, external_bank_account, path=["response"]) + + @parametrize + def test_raw_response_create_overload_4(self, client: Lithic) -> None: + response = client.external_bank_accounts.with_raw_response.create( + account_number="12345678901234567", + country="USD", + currency="USD", + owner="owner", + owner_type="INDIVIDUAL", + routing_number="123456789", + type="CHECKING", + verification_method="UNVERIFIED", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_bank_account = response.parse() + assert_matches_type(ExternalBankAccountCreateResponse, external_bank_account, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_4(self, client: Lithic) -> None: + with client.external_bank_accounts.with_streaming_response.create( + account_number="12345678901234567", + country="USD", + currency="USD", + owner="owner", + owner_type="INDIVIDUAL", + routing_number="123456789", + type="CHECKING", + verification_method="UNVERIFIED", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_bank_account = response.parse() + assert_matches_type(ExternalBankAccountCreateResponse, external_bank_account, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_retrieve(self, client: Lithic) -> None: external_bank_account = client.external_bank_accounts.retrieve( @@ -713,6 +793,86 @@ async def test_streaming_response_create_overload_3(self, async_client: AsyncLit assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_create_overload_4(self, async_client: AsyncLithic) -> None: + external_bank_account = await async_client.external_bank_accounts.create( + account_number="12345678901234567", + country="USD", + currency="USD", + owner="owner", + owner_type="INDIVIDUAL", + routing_number="123456789", + type="CHECKING", + verification_method="UNVERIFIED", + ) + assert_matches_type(ExternalBankAccountCreateResponse, external_bank_account, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_4(self, async_client: AsyncLithic) -> None: + external_bank_account = await async_client.external_bank_accounts.create( + account_number="12345678901234567", + country="USD", + currency="USD", + owner="owner", + owner_type="INDIVIDUAL", + routing_number="123456789", + type="CHECKING", + verification_method="UNVERIFIED", + account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + address={ + "address1": "x", + "city": "x", + "country": "USD", + "postal_code": "11201", + "state": "xx", + "address2": "x", + }, + company_id="sq", + dob=parse_date("2019-12-27"), + doing_business_as="x", + name="name", + user_defined_id="x", + ) + assert_matches_type(ExternalBankAccountCreateResponse, external_bank_account, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_4(self, async_client: AsyncLithic) -> None: + response = await async_client.external_bank_accounts.with_raw_response.create( + account_number="12345678901234567", + country="USD", + currency="USD", + owner="owner", + owner_type="INDIVIDUAL", + routing_number="123456789", + type="CHECKING", + verification_method="UNVERIFIED", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + external_bank_account = response.parse() + assert_matches_type(ExternalBankAccountCreateResponse, external_bank_account, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_4(self, async_client: AsyncLithic) -> None: + async with async_client.external_bank_accounts.with_streaming_response.create( + account_number="12345678901234567", + country="USD", + currency="USD", + owner="owner", + owner_type="INDIVIDUAL", + routing_number="123456789", + type="CHECKING", + verification_method="UNVERIFIED", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + external_bank_account = await response.parse() + assert_matches_type(ExternalBankAccountCreateResponse, external_bank_account, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_retrieve(self, async_client: AsyncLithic) -> None: external_bank_account = await async_client.external_bank_accounts.retrieve( diff --git a/tests/api_resources/test_payments.py b/tests/api_resources/test_payments.py index f409a78f..5857f51f 100644 --- a/tests/api_resources/test_payments.py +++ b/tests/api_resources/test_payments.py @@ -46,7 +46,10 @@ def test_method_create_with_all_params(self, client: Lithic) -> None: external_bank_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", method="ACH_NEXT_DAY", - method_attributes={"sec_code": "CCD"}, + method_attributes={ + "sec_code": "CCD", + "addenda": "addenda", + }, type="COLLECTION", token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", memo="memo", @@ -404,7 +407,10 @@ async def test_method_create_with_all_params(self, async_client: AsyncLithic) -> external_bank_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", financial_account_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", method="ACH_NEXT_DAY", - method_attributes={"sec_code": "CCD"}, + method_attributes={ + "sec_code": "CCD", + "addenda": "addenda", + }, type="COLLECTION", token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", memo="memo", diff --git a/tests/api_resources/three_ds/test_authentication.py b/tests/api_resources/three_ds/test_authentication.py index afc195f1..05d603ca 100644 --- a/tests/api_resources/three_ds/test_authentication.py +++ b/tests/api_resources/three_ds/test_authentication.py @@ -71,8 +71,8 @@ def test_method_simulate(self, client: Lithic) -> None: }, pan="4111111289144142", transaction={ - "amount": 100, - "currency": "USD", + "amount": 0, + "currency": "GBP", }, ) assert_matches_type(AuthenticationSimulateResponse, authentication, path=["response"]) @@ -88,8 +88,8 @@ def test_method_simulate_with_all_params(self, client: Lithic) -> None: }, pan="4111111289144142", transaction={ - "amount": 100, - "currency": "USD", + "amount": 0, + "currency": "GBP", }, card_expiry_check="MATCH", ) @@ -106,8 +106,8 @@ def test_raw_response_simulate(self, client: Lithic) -> None: }, pan="4111111289144142", transaction={ - "amount": 100, - "currency": "USD", + "amount": 0, + "currency": "GBP", }, ) @@ -127,8 +127,8 @@ def test_streaming_response_simulate(self, client: Lithic) -> None: }, pan="4111111289144142", transaction={ - "amount": 100, - "currency": "USD", + "amount": 0, + "currency": "GBP", }, ) as response: assert not response.is_closed @@ -230,8 +230,8 @@ async def test_method_simulate(self, async_client: AsyncLithic) -> None: }, pan="4111111289144142", transaction={ - "amount": 100, - "currency": "USD", + "amount": 0, + "currency": "GBP", }, ) assert_matches_type(AuthenticationSimulateResponse, authentication, path=["response"]) @@ -247,8 +247,8 @@ async def test_method_simulate_with_all_params(self, async_client: AsyncLithic) }, pan="4111111289144142", transaction={ - "amount": 100, - "currency": "USD", + "amount": 0, + "currency": "GBP", }, card_expiry_check="MATCH", ) @@ -265,8 +265,8 @@ async def test_raw_response_simulate(self, async_client: AsyncLithic) -> None: }, pan="4111111289144142", transaction={ - "amount": 100, - "currency": "USD", + "amount": 0, + "currency": "GBP", }, ) @@ -286,8 +286,8 @@ async def test_streaming_response_simulate(self, async_client: AsyncLithic) -> N }, pan="4111111289144142", transaction={ - "amount": 100, - "currency": "USD", + "amount": 0, + "currency": "GBP", }, ) as response: assert not response.is_closed