From eb6c135106a0e11e15aa6245db72a019ea90668e Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 22 Nov 2024 11:23:21 +0000
Subject: [PATCH 1/8] chore(internal): fix compat model_dump method when
warnings are passed (#633)
---
src/lithic/_compat.py | 3 ++-
tests/test_models.py | 8 ++++++++
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/lithic/_compat.py b/src/lithic/_compat.py
index 4794129c..df173f85 100644
--- a/src/lithic/_compat.py
+++ b/src/lithic/_compat.py
@@ -145,7 +145,8 @@ def model_dump(
exclude=exclude,
exclude_unset=exclude_unset,
exclude_defaults=exclude_defaults,
- warnings=warnings,
+ # warnings are not supported in Pydantic v1
+ warnings=warnings if PYDANTIC_V2 else True,
)
return cast(
"dict[str, Any]",
diff --git a/tests/test_models.py b/tests/test_models.py
index 620ea7e3..790991b5 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -561,6 +561,14 @@ class Model(BaseModel):
m.model_dump(warnings=False)
+def test_compat_method_no_error_for_warnings() -> None:
+ class Model(BaseModel):
+ foo: Optional[str]
+
+ m = Model(foo="hello")
+ assert isinstance(model_dump(m, warnings=False), dict)
+
+
def test_to_json() -> None:
class Model(BaseModel):
foo: Optional[str] = Field(alias="FOO", default=None)
From aed46f67456c19cf389275607f593e8e269e3237 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 22 Nov 2024 16:08:09 +0000
Subject: [PATCH 2/8] docs: add info log level to readme (#635)
---
README.md | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 32b45dbf..f7588143 100644
--- a/README.md
+++ b/README.md
@@ -295,12 +295,14 @@ client = Lithic(
We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.
-You can enable logging by setting the environment variable `LITHIC_LOG` to `debug`.
+You can enable logging by setting the environment variable `LITHIC_LOG` to `info`.
```shell
-$ export LITHIC_LOG=debug
+$ export LITHIC_LOG=info
```
+Or to `debug` for more verbose logging.
+
### How to tell whether `None` means `null` or missing
In an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:
From 78321efbac2e6da20afb852d6bf38fa371751d99 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 25 Nov 2024 12:24:33 +0000
Subject: [PATCH 3/8] chore: remove now unused `cached-property` dep (#636)
---
pyproject.toml | 1 -
src/lithic/_compat.py | 5 +----
2 files changed, 1 insertion(+), 5 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 0957c843..ed9ddfff 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -14,7 +14,6 @@ dependencies = [
"anyio>=3.5.0, <5",
"distro>=1.7.0, <2",
"sniffio",
- "cached-property; python_version < '3.8'",
]
requires-python = ">= 3.8"
classifiers = [
diff --git a/src/lithic/_compat.py b/src/lithic/_compat.py
index df173f85..92d9ee61 100644
--- a/src/lithic/_compat.py
+++ b/src/lithic/_compat.py
@@ -214,9 +214,6 @@ def __set_name__(self, owner: type[Any], name: str) -> None: ...
# __set__ is not defined at runtime, but @cached_property is designed to be settable
def __set__(self, instance: object, value: _T) -> None: ...
else:
- try:
- from functools import cached_property as cached_property
- except ImportError:
- from cached_property import cached_property as cached_property
+ from functools import cached_property as cached_property
typed_cached_property = cached_property
From 6436634a1a0ccc9b6ec070c2553bdb45ab656dd6 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 25 Nov 2024 21:20:46 +0000
Subject: [PATCH 4/8] feat(api): updates to Auth Rules numeric types, new Card
Types and Authorization Rule Backtests (#637)
- Specifies numeric types on Auth Rules to be integers
- adds `replacement_for` field to Card create requests
- improvements to documentation
- adds Authorization Rules Backtests
---
src/lithic/resources/cards/cards.py | 12 +-
.../resources/transactions/transactions.py | 192 +++++++++---------
.../types/auth_rules/v2_apply_response.py | 5 +-
.../types/auth_rules/v2_create_params.py | 6 +-
.../types/auth_rules/v2_create_response.py | 5 +-
.../types/auth_rules/v2_draft_params.py | 2 +-
.../types/auth_rules/v2_draft_response.py | 5 +-
.../types/auth_rules/v2_list_response.py | 5 +-
.../types/auth_rules/v2_promote_response.py | 5 +-
.../types/auth_rules/v2_retrieve_response.py | 5 +-
.../types/auth_rules/v2_update_response.py | 5 +-
src/lithic/types/card.py | 12 +-
src/lithic/types/card_create_params.py | 6 +-
.../types/shared/velocity_limit_params.py | 6 +-
.../shared_params/velocity_limit_params.py | 6 +-
.../authentication_retrieve_response.py | 6 +-
src/lithic/types/transaction.py | 33 +--
...on_simulate_authorization_advice_params.py | 2 +-
...ansaction_simulate_authorization_params.py | 12 +-
.../transaction_simulate_clearing_params.py | 14 +-
.../types/transaction_simulate_void_params.py | 3 +-
21 files changed, 196 insertions(+), 151 deletions(-)
diff --git a/src/lithic/resources/cards/cards.py b/src/lithic/resources/cards/cards.py
index 69f559f0..1139d633 100644
--- a/src/lithic/resources/cards/cards.py
+++ b/src/lithic/resources/cards/cards.py
@@ -113,7 +113,7 @@ def with_streaming_response(self) -> CardsWithStreamingResponse:
def create(
self,
*,
- type: Literal["MERCHANT_LOCKED", "PHYSICAL", "SINGLE_USE", "VIRTUAL"],
+ type: Literal["MERCHANT_LOCKED", "PHYSICAL", "SINGLE_USE", "VIRTUAL", "UNLOCKED", "DIGITAL_WALLET"],
account_token: str | NotGiven = NOT_GIVEN,
card_program_token: str | NotGiven = NOT_GIVEN,
carrier: Carrier | NotGiven = NOT_GIVEN,
@@ -157,6 +157,10 @@ def create(
- `SINGLE_USE` - Card is closed upon first successful authorization.
- `MERCHANT_LOCKED` - _[Deprecated]_ Card is locked to the first merchant that
successfully authorizes the card.
+ - `UNLOCKED` - _[Deprecated]_ Similar behavior to VIRTUAL cards, please use
+ VIRTUAL instead.
+ - `DIGITAL_WALLET` - _[Deprecated]_ Similar behavior to VIRTUAL cards, please
+ use VIRTUAL instead.
account_token: Globally unique identifier for the account that the card will be associated
with. Required for programs enrolling users using the
@@ -1006,7 +1010,7 @@ def with_streaming_response(self) -> AsyncCardsWithStreamingResponse:
async def create(
self,
*,
- type: Literal["MERCHANT_LOCKED", "PHYSICAL", "SINGLE_USE", "VIRTUAL"],
+ type: Literal["MERCHANT_LOCKED", "PHYSICAL", "SINGLE_USE", "VIRTUAL", "UNLOCKED", "DIGITAL_WALLET"],
account_token: str | NotGiven = NOT_GIVEN,
card_program_token: str | NotGiven = NOT_GIVEN,
carrier: Carrier | NotGiven = NOT_GIVEN,
@@ -1050,6 +1054,10 @@ async def create(
- `SINGLE_USE` - Card is closed upon first successful authorization.
- `MERCHANT_LOCKED` - _[Deprecated]_ Card is locked to the first merchant that
successfully authorizes the card.
+ - `UNLOCKED` - _[Deprecated]_ Similar behavior to VIRTUAL cards, please use
+ VIRTUAL instead.
+ - `DIGITAL_WALLET` - _[Deprecated]_ Similar behavior to VIRTUAL cards, please
+ use VIRTUAL instead.
account_token: Globally unique identifier for the account that the card will be associated
with. Required for programs enrolling users using the
diff --git a/src/lithic/resources/transactions/transactions.py b/src/lithic/resources/transactions/transactions.py
index 6e94ec8a..eebb2a7c 100644
--- a/src/lithic/resources/transactions/transactions.py
+++ b/src/lithic/resources/transactions/transactions.py
@@ -226,19 +226,20 @@ def simulate_authorization(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> TransactionSimulateAuthorizationResponse:
"""
- Simulates an authorization request from the payment network as if it came from a
- merchant acquirer. If you're configured for ASA, simulating auths requires your
- ASA client to be set up properly (respond with a valid JSON to the ASA request).
- For users that are not configured for ASA, a daily transaction limit of $5000
- USD is applied by default. This limit can be modified via the
+ Simulates an authorization request from the card network as if it came from a
+ merchant acquirer. If you are configured for ASA, simulating authorizations
+ requires your ASA client to be set up properly, i.e. be able to respond to the
+ ASA request with a valid JSON. For users that are not configured for ASA, a
+ daily transaction limit of $5000 USD is applied by default. You can update this
+ limit via the
[update account](https://docs.lithic.com/reference/patchaccountbytoken)
endpoint.
Args:
amount: Amount (in cents) to authorize. For credit authorizations and financial credit
authorizations, any value entered will be converted into a negative amount in
- the simulated transaction. For example, entering 100 in this field will appear
- as a -100 amount in the transaction. For balance inquiries, this field must be
+ the simulated transaction. For example, entering 100 in this field will result
+ in a -100 amount in the transaction. For balance inquiries, this field must be
set to 0.
descriptor: Merchant descriptor.
@@ -265,12 +266,12 @@ def simulate_authorization(
- `AUTHORIZATION` is a dual message purchase authorization, meaning a subsequent
clearing step is required to settle the transaction.
- - `BALANCE_INQUIRY` is a $0 authorization that includes a request for the
- balance held on the card, and is most typically seen when a cardholder
- requests to view a card's balance at an ATM.
+ - `BALANCE_INQUIRY` is a $0 authorization requesting the balance held on the
+ card, and is most often observed when a cardholder requests to view a card's
+ balance at an ATM.
- `CREDIT_AUTHORIZATION` is a dual message request from a merchant to authorize
- a refund or credit, meaning a subsequent clearing step is required to settle
- the transaction.
+ a refund, meaning a subsequent clearing step is required to settle the
+ transaction.
- `FINANCIAL_AUTHORIZATION` is a single message request from a merchant to debit
funds immediately (such as an ATM withdrawal), and no subsequent clearing is
required to settle the transaction.
@@ -321,12 +322,12 @@ def simulate_authorization_advice(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> TransactionSimulateAuthorizationAdviceResponse:
"""
- Simulates an authorization advice request from the payment network as if it came
- from a merchant acquirer. An authorization advice request changes the amount of
- the transaction.
+ Simulates an authorization advice from the card network as if it came from a
+ merchant acquirer. An authorization advice changes the pending amount of the
+ transaction.
Args:
- token: The transaction token returned from the /v1/simulate/authorize response.
+ token: The transaction token returned from the /v1/simulate/authorize. response.
amount: Amount (in cents) to authorize. This amount will override the transaction's
amount that was originally set by /v1/simulate/authorize.
@@ -366,24 +367,27 @@ def simulate_clearing(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> TransactionSimulateClearingResponse:
- """Clears an existing authorization.
+ """Clears an existing authorization, either debit or credit.
- After this event, the transaction is no longer
- pending.
+ After this event, the
+ transaction transitions from `PENDING` to `SETTLED` status.
- If no `amount` is supplied to this endpoint, the amount of the transaction will
- be captured. Any transaction that has any amount completed at all do not have
- access to this behavior.
+ If `amount` is not set, the full amount of the transaction will be cleared.
+ Transactions that have already cleared, either partially or fully, cannot be
+ cleared again using this endpoint.
Args:
token: The transaction token returned from the /v1/simulate/authorize response.
- amount: Amount (in cents) to complete. Typically this will match the original
- authorization, but may be more or less.
+ amount: Amount (in cents) to clear. Typically this will match the amount in the original
+ authorization, but can be higher or lower. The sign of this amount will
+ automatically match the sign of the original authorization's amount. For
+ example, entering 100 in this field will result in a -100 amount in the
+ transaction, if the original authorization is a credit authorization.
- If no amount is supplied to this endpoint, the amount of the transaction will be
- captured. Any transaction that has any amount completed at all do not have
- access to this behavior.
+ If `amount` is not set, the full amount of the transaction will be cleared.
+ Transactions that have already cleared, either partially or fully, cannot be
+ cleared again using this endpoint.
extra_headers: Send extra headers
@@ -423,11 +427,10 @@ def simulate_credit_authorization(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> TransactionSimulateCreditAuthorizationResponse:
- """Simulates a credit authorization advice message from the payment network.
+ """Simulates a credit authorization advice from the card network.
- This
- message indicates that a credit authorization was approved on your behalf by the
- network.
+ This message
+ indicates that the network approved a credit authorization on your behalf.
Args:
amount: Amount (in cents). Any value entered will be converted into a negative amount in
@@ -483,10 +486,11 @@ def simulate_return(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> TransactionSimulateReturnResponse:
- """Returns (aka refunds) an amount back to a card.
+ """Returns, or refunds, an amount back to a card.
- Returns are cleared immediately
- and do not spend time in a `PENDING` state.
+ Returns simulated via this
+ endpoint clear immediately, without prior authorization, and result in a
+ `SETTLED` transaction status.
Args:
amount: Amount (in cents) to authorize.
@@ -530,10 +534,11 @@ def simulate_return_reversal(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> TransactionSimulateReturnReversalResponse:
- """
- Voids a settled credit transaction – i.e., a transaction with a negative amount
- and `SETTLED` status. These can be credit authorizations that have already
- cleared or financial credit authorizations.
+ """Reverses a return, i.e.
+
+ a credit transaction with a `SETTLED` status. Returns
+ can be financial credit authorizations, or credit authorizations that have
+ cleared.
Args:
token: The transaction token returned from the /v1/simulate/authorize response.
@@ -570,19 +575,18 @@ def simulate_void(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> TransactionSimulateVoidResponse:
- """Voids an existing, uncleared (aka pending) authorization.
+ """Voids a pending authorization.
- If amount is not sent
- the full amount will be voided. Cannot be used on partially completed
- transactions, but can be used on partially voided transactions. _Note that
- simulating an authorization expiry on credit authorizations or credit
- authorization advice is not currently supported but will be added soon._
+ If `amount` is not set, the full amount will be
+ voided. Can be used on partially voided transactions but not partially cleared
+ transactions. _Simulating an authorization expiry on credit authorizations or
+ credit authorization advice is not currently supported but will be added soon._
Args:
token: The transaction token returned from the /v1/simulate/authorize response.
- amount: Amount (in cents) to void. Typically this will match the original authorization,
- but may be less.
+ amount: Amount (in cents) to void. Typically this will match the amount in the original
+ authorization, but can be less.
type: Type of event to simulate. Defaults to `AUTHORIZATION_REVERSAL`.
@@ -783,19 +787,20 @@ async def simulate_authorization(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> TransactionSimulateAuthorizationResponse:
"""
- Simulates an authorization request from the payment network as if it came from a
- merchant acquirer. If you're configured for ASA, simulating auths requires your
- ASA client to be set up properly (respond with a valid JSON to the ASA request).
- For users that are not configured for ASA, a daily transaction limit of $5000
- USD is applied by default. This limit can be modified via the
+ Simulates an authorization request from the card network as if it came from a
+ merchant acquirer. If you are configured for ASA, simulating authorizations
+ requires your ASA client to be set up properly, i.e. be able to respond to the
+ ASA request with a valid JSON. For users that are not configured for ASA, a
+ daily transaction limit of $5000 USD is applied by default. You can update this
+ limit via the
[update account](https://docs.lithic.com/reference/patchaccountbytoken)
endpoint.
Args:
amount: Amount (in cents) to authorize. For credit authorizations and financial credit
authorizations, any value entered will be converted into a negative amount in
- the simulated transaction. For example, entering 100 in this field will appear
- as a -100 amount in the transaction. For balance inquiries, this field must be
+ the simulated transaction. For example, entering 100 in this field will result
+ in a -100 amount in the transaction. For balance inquiries, this field must be
set to 0.
descriptor: Merchant descriptor.
@@ -822,12 +827,12 @@ async def simulate_authorization(
- `AUTHORIZATION` is a dual message purchase authorization, meaning a subsequent
clearing step is required to settle the transaction.
- - `BALANCE_INQUIRY` is a $0 authorization that includes a request for the
- balance held on the card, and is most typically seen when a cardholder
- requests to view a card's balance at an ATM.
+ - `BALANCE_INQUIRY` is a $0 authorization requesting the balance held on the
+ card, and is most often observed when a cardholder requests to view a card's
+ balance at an ATM.
- `CREDIT_AUTHORIZATION` is a dual message request from a merchant to authorize
- a refund or credit, meaning a subsequent clearing step is required to settle
- the transaction.
+ a refund, meaning a subsequent clearing step is required to settle the
+ transaction.
- `FINANCIAL_AUTHORIZATION` is a single message request from a merchant to debit
funds immediately (such as an ATM withdrawal), and no subsequent clearing is
required to settle the transaction.
@@ -878,12 +883,12 @@ async def simulate_authorization_advice(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> TransactionSimulateAuthorizationAdviceResponse:
"""
- Simulates an authorization advice request from the payment network as if it came
- from a merchant acquirer. An authorization advice request changes the amount of
- the transaction.
+ Simulates an authorization advice from the card network as if it came from a
+ merchant acquirer. An authorization advice changes the pending amount of the
+ transaction.
Args:
- token: The transaction token returned from the /v1/simulate/authorize response.
+ token: The transaction token returned from the /v1/simulate/authorize. response.
amount: Amount (in cents) to authorize. This amount will override the transaction's
amount that was originally set by /v1/simulate/authorize.
@@ -923,24 +928,27 @@ async def simulate_clearing(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> TransactionSimulateClearingResponse:
- """Clears an existing authorization.
+ """Clears an existing authorization, either debit or credit.
- After this event, the transaction is no longer
- pending.
+ After this event, the
+ transaction transitions from `PENDING` to `SETTLED` status.
- If no `amount` is supplied to this endpoint, the amount of the transaction will
- be captured. Any transaction that has any amount completed at all do not have
- access to this behavior.
+ If `amount` is not set, the full amount of the transaction will be cleared.
+ Transactions that have already cleared, either partially or fully, cannot be
+ cleared again using this endpoint.
Args:
token: The transaction token returned from the /v1/simulate/authorize response.
- amount: Amount (in cents) to complete. Typically this will match the original
- authorization, but may be more or less.
+ amount: Amount (in cents) to clear. Typically this will match the amount in the original
+ authorization, but can be higher or lower. The sign of this amount will
+ automatically match the sign of the original authorization's amount. For
+ example, entering 100 in this field will result in a -100 amount in the
+ transaction, if the original authorization is a credit authorization.
- If no amount is supplied to this endpoint, the amount of the transaction will be
- captured. Any transaction that has any amount completed at all do not have
- access to this behavior.
+ If `amount` is not set, the full amount of the transaction will be cleared.
+ Transactions that have already cleared, either partially or fully, cannot be
+ cleared again using this endpoint.
extra_headers: Send extra headers
@@ -980,11 +988,10 @@ async def simulate_credit_authorization(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> TransactionSimulateCreditAuthorizationResponse:
- """Simulates a credit authorization advice message from the payment network.
+ """Simulates a credit authorization advice from the card network.
- This
- message indicates that a credit authorization was approved on your behalf by the
- network.
+ This message
+ indicates that the network approved a credit authorization on your behalf.
Args:
amount: Amount (in cents). Any value entered will be converted into a negative amount in
@@ -1040,10 +1047,11 @@ async def simulate_return(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> TransactionSimulateReturnResponse:
- """Returns (aka refunds) an amount back to a card.
+ """Returns, or refunds, an amount back to a card.
- Returns are cleared immediately
- and do not spend time in a `PENDING` state.
+ Returns simulated via this
+ endpoint clear immediately, without prior authorization, and result in a
+ `SETTLED` transaction status.
Args:
amount: Amount (in cents) to authorize.
@@ -1087,10 +1095,11 @@ async def simulate_return_reversal(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> TransactionSimulateReturnReversalResponse:
- """
- Voids a settled credit transaction – i.e., a transaction with a negative amount
- and `SETTLED` status. These can be credit authorizations that have already
- cleared or financial credit authorizations.
+ """Reverses a return, i.e.
+
+ a credit transaction with a `SETTLED` status. Returns
+ can be financial credit authorizations, or credit authorizations that have
+ cleared.
Args:
token: The transaction token returned from the /v1/simulate/authorize response.
@@ -1127,19 +1136,18 @@ async def simulate_void(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> TransactionSimulateVoidResponse:
- """Voids an existing, uncleared (aka pending) authorization.
+ """Voids a pending authorization.
- If amount is not sent
- the full amount will be voided. Cannot be used on partially completed
- transactions, but can be used on partially voided transactions. _Note that
- simulating an authorization expiry on credit authorizations or credit
- authorization advice is not currently supported but will be added soon._
+ If `amount` is not set, the full amount will be
+ voided. Can be used on partially voided transactions but not partially cleared
+ transactions. _Simulating an authorization expiry on credit authorizations or
+ credit authorization advice is not currently supported but will be added soon._
Args:
token: The transaction token returned from the /v1/simulate/authorize response.
- amount: Amount (in cents) to void. Typically this will match the original authorization,
- but may be less.
+ amount: Amount (in cents) to void. Typically this will match the amount in the original
+ authorization, but can be less.
type: Type of event to simulate. Defaults to `AUTHORIZATION_REVERSAL`.
diff --git a/src/lithic/types/auth_rules/v2_apply_response.py b/src/lithic/types/auth_rules/v2_apply_response.py
index 970dfa0a..4a0aac7a 100644
--- a/src/lithic/types/auth_rules/v2_apply_response.py
+++ b/src/lithic/types/auth_rules/v2_apply_response.py
@@ -71,7 +71,7 @@ class CurrentVersionParametersConditionalBlockParametersCondition(BaseModel):
] = None
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str], None] = None
+ value: Union[str, int, List[str], None] = None
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -145,7 +145,7 @@ class DraftVersionParametersConditionalBlockParametersCondition(BaseModel):
] = None
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str], None] = None
+ value: Union[str, int, List[str], None] = None
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -169,6 +169,7 @@ class DraftVersion(BaseModel):
class V2ApplyResponse(BaseModel):
token: str
+ """Auth Rule Token"""
account_tokens: List[str]
"""Account tokens to which the Auth Rule applies."""
diff --git a/src/lithic/types/auth_rules/v2_create_params.py b/src/lithic/types/auth_rules/v2_create_params.py
index b749e726..a6be31a1 100644
--- a/src/lithic/types/auth_rules/v2_create_params.py
+++ b/src/lithic/types/auth_rules/v2_create_params.py
@@ -83,7 +83,7 @@ class CreateAuthRuleRequestAccountTokensParametersConditionalBlockParametersCond
operation: Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"]
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str]]
+ value: Union[str, int, List[str]]
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -155,7 +155,7 @@ class CreateAuthRuleRequestCardTokensParametersConditionalBlockParametersConditi
operation: Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"]
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str]]
+ value: Union[str, int, List[str]]
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -227,7 +227,7 @@ class CreateAuthRuleRequestProgramLevelParametersConditionalBlockParametersCondi
operation: Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"]
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str]]
+ value: Union[str, int, List[str]]
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
diff --git a/src/lithic/types/auth_rules/v2_create_response.py b/src/lithic/types/auth_rules/v2_create_response.py
index 6ee72e59..976aeb4d 100644
--- a/src/lithic/types/auth_rules/v2_create_response.py
+++ b/src/lithic/types/auth_rules/v2_create_response.py
@@ -71,7 +71,7 @@ class CurrentVersionParametersConditionalBlockParametersCondition(BaseModel):
] = None
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str], None] = None
+ value: Union[str, int, List[str], None] = None
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -145,7 +145,7 @@ class DraftVersionParametersConditionalBlockParametersCondition(BaseModel):
] = None
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str], None] = None
+ value: Union[str, int, List[str], None] = None
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -169,6 +169,7 @@ class DraftVersion(BaseModel):
class V2CreateResponse(BaseModel):
token: str
+ """Auth Rule Token"""
account_tokens: List[str]
"""Account tokens to which the Auth Rule applies."""
diff --git a/src/lithic/types/auth_rules/v2_draft_params.py b/src/lithic/types/auth_rules/v2_draft_params.py
index a22e7038..382c7f72 100644
--- a/src/lithic/types/auth_rules/v2_draft_params.py
+++ b/src/lithic/types/auth_rules/v2_draft_params.py
@@ -68,7 +68,7 @@ class ParametersConditionalBlockParametersCondition(TypedDict, total=False):
operation: Literal["IS_ONE_OF", "IS_NOT_ONE_OF", "MATCHES", "DOES_NOT_MATCH", "IS_GREATER_THAN", "IS_LESS_THAN"]
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str]]
+ value: Union[str, int, List[str]]
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
diff --git a/src/lithic/types/auth_rules/v2_draft_response.py b/src/lithic/types/auth_rules/v2_draft_response.py
index fd8be59a..516b2db7 100644
--- a/src/lithic/types/auth_rules/v2_draft_response.py
+++ b/src/lithic/types/auth_rules/v2_draft_response.py
@@ -71,7 +71,7 @@ class CurrentVersionParametersConditionalBlockParametersCondition(BaseModel):
] = None
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str], None] = None
+ value: Union[str, int, List[str], None] = None
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -145,7 +145,7 @@ class DraftVersionParametersConditionalBlockParametersCondition(BaseModel):
] = None
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str], None] = None
+ value: Union[str, int, List[str], None] = None
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -169,6 +169,7 @@ class DraftVersion(BaseModel):
class V2DraftResponse(BaseModel):
token: str
+ """Auth Rule Token"""
account_tokens: List[str]
"""Account tokens to which the Auth Rule applies."""
diff --git a/src/lithic/types/auth_rules/v2_list_response.py b/src/lithic/types/auth_rules/v2_list_response.py
index 648ce243..b1ac2cc3 100644
--- a/src/lithic/types/auth_rules/v2_list_response.py
+++ b/src/lithic/types/auth_rules/v2_list_response.py
@@ -71,7 +71,7 @@ class CurrentVersionParametersConditionalBlockParametersCondition(BaseModel):
] = None
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str], None] = None
+ value: Union[str, int, List[str], None] = None
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -145,7 +145,7 @@ class DraftVersionParametersConditionalBlockParametersCondition(BaseModel):
] = None
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str], None] = None
+ value: Union[str, int, List[str], None] = None
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -169,6 +169,7 @@ class DraftVersion(BaseModel):
class V2ListResponse(BaseModel):
token: str
+ """Auth Rule Token"""
account_tokens: List[str]
"""Account tokens to which the Auth Rule applies."""
diff --git a/src/lithic/types/auth_rules/v2_promote_response.py b/src/lithic/types/auth_rules/v2_promote_response.py
index 645ebb9d..1ec1e7e3 100644
--- a/src/lithic/types/auth_rules/v2_promote_response.py
+++ b/src/lithic/types/auth_rules/v2_promote_response.py
@@ -71,7 +71,7 @@ class CurrentVersionParametersConditionalBlockParametersCondition(BaseModel):
] = None
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str], None] = None
+ value: Union[str, int, List[str], None] = None
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -145,7 +145,7 @@ class DraftVersionParametersConditionalBlockParametersCondition(BaseModel):
] = None
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str], None] = None
+ value: Union[str, int, List[str], None] = None
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -169,6 +169,7 @@ class DraftVersion(BaseModel):
class V2PromoteResponse(BaseModel):
token: str
+ """Auth Rule Token"""
account_tokens: List[str]
"""Account tokens to which the Auth Rule applies."""
diff --git a/src/lithic/types/auth_rules/v2_retrieve_response.py b/src/lithic/types/auth_rules/v2_retrieve_response.py
index cb834d9b..9f1e3ffb 100644
--- a/src/lithic/types/auth_rules/v2_retrieve_response.py
+++ b/src/lithic/types/auth_rules/v2_retrieve_response.py
@@ -71,7 +71,7 @@ class CurrentVersionParametersConditionalBlockParametersCondition(BaseModel):
] = None
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str], None] = None
+ value: Union[str, int, List[str], None] = None
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -145,7 +145,7 @@ class DraftVersionParametersConditionalBlockParametersCondition(BaseModel):
] = None
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str], None] = None
+ value: Union[str, int, List[str], None] = None
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -169,6 +169,7 @@ class DraftVersion(BaseModel):
class V2RetrieveResponse(BaseModel):
token: str
+ """Auth Rule Token"""
account_tokens: List[str]
"""Account tokens to which the Auth Rule applies."""
diff --git a/src/lithic/types/auth_rules/v2_update_response.py b/src/lithic/types/auth_rules/v2_update_response.py
index fffb3e9f..967ecd99 100644
--- a/src/lithic/types/auth_rules/v2_update_response.py
+++ b/src/lithic/types/auth_rules/v2_update_response.py
@@ -71,7 +71,7 @@ class CurrentVersionParametersConditionalBlockParametersCondition(BaseModel):
] = None
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str], None] = None
+ value: Union[str, int, List[str], None] = None
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -145,7 +145,7 @@ class DraftVersionParametersConditionalBlockParametersCondition(BaseModel):
] = None
"""The operation to apply to the attribute"""
- value: Union[str, float, List[str], None] = None
+ value: Union[str, int, List[str], None] = None
"""A regex string, to be used with `MATCHES` or `DOES_NOT_MATCH`"""
@@ -169,6 +169,7 @@ class DraftVersion(BaseModel):
class V2UpdateResponse(BaseModel):
token: str
+ """Auth Rule Token"""
account_tokens: List[str]
"""Account tokens to which the Auth Rule applies."""
diff --git a/src/lithic/types/card.py b/src/lithic/types/card.py
index 5ff38920..a31ff96a 100644
--- a/src/lithic/types/card.py
+++ b/src/lithic/types/card.py
@@ -121,7 +121,7 @@ class Card(BaseModel):
manufactured.
"""
- type: Literal["MERCHANT_LOCKED", "PHYSICAL", "SINGLE_USE", "VIRTUAL"]
+ type: Literal["MERCHANT_LOCKED", "PHYSICAL", "SINGLE_USE", "VIRTUAL", "UNLOCKED", "DIGITAL_WALLET"]
"""Card types:
- `VIRTUAL` - Card will authorize at any merchant and can be added to a digital
@@ -134,6 +134,10 @@ class Card(BaseModel):
- `SINGLE_USE` - Card is closed upon first successful authorization.
- `MERCHANT_LOCKED` - _[Deprecated]_ Card is locked to the first merchant that
successfully authorizes the card.
+ - `UNLOCKED` - _[Deprecated]_ Similar behavior to VIRTUAL cards, please use
+ VIRTUAL instead.
+ - `DIGITAL_WALLET` - _[Deprecated]_ Similar behavior to VIRTUAL cards, please
+ use VIRTUAL instead.
"""
auth_rule_tokens: Optional[List[str]] = None
@@ -191,3 +195,9 @@ class Card(BaseModel):
This must be configured with Lithic before use. Specifies the configuration
(i.e., physical card art) that the card should be manufactured with.
"""
+
+ replacement_for: Optional[str] = None
+ """
+ If the card is a replacement for another card, the globally unique identifier
+ for the card that was replaced.
+ """
diff --git a/src/lithic/types/card_create_params.py b/src/lithic/types/card_create_params.py
index bcd5d2f5..01c5e9a1 100644
--- a/src/lithic/types/card_create_params.py
+++ b/src/lithic/types/card_create_params.py
@@ -12,7 +12,7 @@
class CardCreateParams(TypedDict, total=False):
- type: Required[Literal["MERCHANT_LOCKED", "PHYSICAL", "SINGLE_USE", "VIRTUAL"]]
+ type: Required[Literal["MERCHANT_LOCKED", "PHYSICAL", "SINGLE_USE", "VIRTUAL", "UNLOCKED", "DIGITAL_WALLET"]]
"""Card types:
- `VIRTUAL` - Card will authorize at any merchant and can be added to a digital
@@ -25,6 +25,10 @@ class CardCreateParams(TypedDict, total=False):
- `SINGLE_USE` - Card is closed upon first successful authorization.
- `MERCHANT_LOCKED` - _[Deprecated]_ Card is locked to the first merchant that
successfully authorizes the card.
+ - `UNLOCKED` - _[Deprecated]_ Similar behavior to VIRTUAL cards, please use
+ VIRTUAL instead.
+ - `DIGITAL_WALLET` - _[Deprecated]_ Similar behavior to VIRTUAL cards, please
+ use VIRTUAL instead.
"""
account_token: str
diff --git a/src/lithic/types/shared/velocity_limit_params.py b/src/lithic/types/shared/velocity_limit_params.py
index 7bac9b17..413a34e2 100644
--- a/src/lithic/types/shared/velocity_limit_params.py
+++ b/src/lithic/types/shared/velocity_limit_params.py
@@ -28,7 +28,7 @@ class Filters(BaseModel):
class VelocityLimitParams(BaseModel):
filters: Filters
- period: Union[float, VelocityLimitParamsPeriodWindow]
+ period: Union[int, VelocityLimitParamsPeriodWindow]
"""The size of the trailing window to calculate Spend Velocity over in seconds.
The minimum value is 10 seconds, and the maximum value is 2678400 seconds.
@@ -36,14 +36,14 @@ class VelocityLimitParams(BaseModel):
scope: Literal["CARD", "ACCOUNT"]
- limit_amount: Optional[float] = None
+ limit_amount: Optional[int] = None
"""
The maximum amount of spend velocity allowed in the period in minor units (the
smallest unit of a currency, e.g. cents for USD). Transactions exceeding this
limit will be declined.
"""
- limit_count: Optional[float] = None
+ limit_count: Optional[int] = None
"""
The number of spend velocity impacting transactions may not exceed this limit in
the period. Transactions exceeding this limit will be declined. A spend velocity
diff --git a/src/lithic/types/shared_params/velocity_limit_params.py b/src/lithic/types/shared_params/velocity_limit_params.py
index 531c4f3d..45d56ff3 100644
--- a/src/lithic/types/shared_params/velocity_limit_params.py
+++ b/src/lithic/types/shared_params/velocity_limit_params.py
@@ -29,7 +29,7 @@ class Filters(TypedDict, total=False):
class VelocityLimitParams(TypedDict, total=False):
filters: Required[Filters]
- period: Required[Union[float, VelocityLimitParamsPeriodWindow]]
+ period: Required[Union[int, VelocityLimitParamsPeriodWindow]]
"""The size of the trailing window to calculate Spend Velocity over in seconds.
The minimum value is 10 seconds, and the maximum value is 2678400 seconds.
@@ -37,14 +37,14 @@ class VelocityLimitParams(TypedDict, total=False):
scope: Required[Literal["CARD", "ACCOUNT"]]
- limit_amount: Optional[float]
+ limit_amount: Optional[int]
"""
The maximum amount of spend velocity allowed in the period in minor units (the
smallest unit of a currency, e.g. cents for USD). Transactions exceeding this
limit will be declined.
"""
- limit_count: Optional[float]
+ limit_count: Optional[int]
"""
The number of spend velocity impacting transactions may not exceed this limit in
the period. Transactions exceeding this limit will be declined. A spend velocity
diff --git a/src/lithic/types/three_ds/authentication_retrieve_response.py b/src/lithic/types/three_ds/authentication_retrieve_response.py
index 515570dd..3b5a068e 100644
--- a/src/lithic/types/three_ds/authentication_retrieve_response.py
+++ b/src/lithic/types/three_ds/authentication_retrieve_response.py
@@ -124,14 +124,14 @@ class MerchantRiskIndicator(BaseModel):
Maps to EMV 3DS field deliveryTimeframe.
"""
- gift_card_amount: Optional[float] = None
+ 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.
"""
- gift_card_count: Optional[float] = None
+ 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.
@@ -218,7 +218,7 @@ class AdditionalData(BaseModel):
authentication request to be low risk or not.
"""
- network_risk_score: Optional[float] = None
+ 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.
diff --git a/src/lithic/types/transaction.py b/src/lithic/types/transaction.py
index d3dfa409..6f6c3797 100644
--- a/src/lithic/types/transaction.py
+++ b/src/lithic/types/transaction.py
@@ -33,12 +33,15 @@
class AmountsCardholder(BaseModel):
amount: int
- """The aggregate settled amount in the cardholder billing currency."""
+ """
+ The estimated settled amount of the transaction in the cardholder billing
+ currency.
+ """
conversion_rate: str
"""
- The conversion rate used to convert the merchant amount to the cardholder
- billing amount.
+ The exchange rate used to convert the merchant amount to the cardholder billing
+ amount.
"""
currency: Currency
@@ -51,10 +54,7 @@ class AmountsCardholder(BaseModel):
class AmountsHold(BaseModel):
amount: int
- """
- The aggregate authorization amount of the transaction in the anticipated
- settlement currency.
- """
+ """The pending amount of the transaction in the anticipated settlement currency."""
currency: Currency
"""ISO 4217 currency.
@@ -66,7 +66,7 @@ class AmountsHold(BaseModel):
class AmountsMerchant(BaseModel):
amount: int
- """The aggregate settled amount in the merchant currency."""
+ """The settled amount of the transaction in the merchant currency."""
currency: Currency
"""ISO 4217 currency.
@@ -78,7 +78,7 @@ class AmountsMerchant(BaseModel):
class AmountsSettlement(BaseModel):
amount: int
- """The aggregate settled amount in the settlement currency."""
+ """The settled amount of the transaction in the settlement currency."""
currency: Currency
"""ISO 4217 currency.
@@ -314,12 +314,12 @@ class TokenInfo(BaseModel):
class EventAmountsCardholder(BaseModel):
amount: int
- """The amount in the cardholder billing currency."""
+ """Amount of the event in the cardholder billing currency."""
conversion_rate: str
"""
- The conversion rate used to convert the merchant amount to the cardholder
- billing amount.
+ Exchange rate used to convert the merchant amount to the cardholder billing
+ amount.
"""
currency: Currency
@@ -332,7 +332,7 @@ class EventAmountsCardholder(BaseModel):
class EventAmountsMerchant(BaseModel):
amount: int
- """The amount in the merchant currency."""
+ """Amount of the event in the merchant currency."""
currency: Currency
"""ISO 4217 currency.
@@ -344,10 +344,13 @@ class EventAmountsMerchant(BaseModel):
class EventAmountsSettlement(BaseModel):
amount: int
- """Amount of the event, if it is financial, in the settlement currency."""
+ """Amount of the event, if it is financial, in the settlement currency.
+
+ Non-financial events do not contain this amount because they do not move funds.
+ """
conversion_rate: str
- """Conversion rate used to convert the merchant amount to the settlement amount."""
+ """Exchange rate used to convert the merchant amount to the settlement amount."""
currency: Currency
"""ISO 4217 currency.
diff --git a/src/lithic/types/transaction_simulate_authorization_advice_params.py b/src/lithic/types/transaction_simulate_authorization_advice_params.py
index 503ec9d5..5e973292 100644
--- a/src/lithic/types/transaction_simulate_authorization_advice_params.py
+++ b/src/lithic/types/transaction_simulate_authorization_advice_params.py
@@ -9,7 +9,7 @@
class TransactionSimulateAuthorizationAdviceParams(TypedDict, total=False):
token: Required[str]
- """The transaction token returned from the /v1/simulate/authorize response."""
+ """The transaction token returned from the /v1/simulate/authorize. response."""
amount: Required[int]
"""Amount (in cents) to authorize.
diff --git a/src/lithic/types/transaction_simulate_authorization_params.py b/src/lithic/types/transaction_simulate_authorization_params.py
index dc48a18c..25cb817d 100644
--- a/src/lithic/types/transaction_simulate_authorization_params.py
+++ b/src/lithic/types/transaction_simulate_authorization_params.py
@@ -13,7 +13,7 @@ class TransactionSimulateAuthorizationParams(TypedDict, total=False):
For credit authorizations and financial credit authorizations, any value entered
will be converted into a negative amount in the simulated transaction. For
- example, entering 100 in this field will appear as a -100 amount in the
+ example, entering 100 in this field will result in a -100 amount in the
transaction. For balance inquiries, this field must be set to 0.
"""
@@ -65,12 +65,12 @@ class TransactionSimulateAuthorizationParams(TypedDict, total=False):
- `AUTHORIZATION` is a dual message purchase authorization, meaning a subsequent
clearing step is required to settle the transaction.
- - `BALANCE_INQUIRY` is a $0 authorization that includes a request for the
- balance held on the card, and is most typically seen when a cardholder
- requests to view a card's balance at an ATM.
+ - `BALANCE_INQUIRY` is a $0 authorization requesting the balance held on the
+ card, and is most often observed when a cardholder requests to view a card's
+ balance at an ATM.
- `CREDIT_AUTHORIZATION` is a dual message request from a merchant to authorize
- a refund or credit, meaning a subsequent clearing step is required to settle
- the transaction.
+ a refund, meaning a subsequent clearing step is required to settle the
+ transaction.
- `FINANCIAL_AUTHORIZATION` is a single message request from a merchant to debit
funds immediately (such as an ATM withdrawal), and no subsequent clearing is
required to settle the transaction.
diff --git a/src/lithic/types/transaction_simulate_clearing_params.py b/src/lithic/types/transaction_simulate_clearing_params.py
index 94475c8e..ab45523f 100644
--- a/src/lithic/types/transaction_simulate_clearing_params.py
+++ b/src/lithic/types/transaction_simulate_clearing_params.py
@@ -12,11 +12,15 @@ class TransactionSimulateClearingParams(TypedDict, total=False):
"""The transaction token returned from the /v1/simulate/authorize response."""
amount: int
- """Amount (in cents) to complete.
+ """Amount (in cents) to clear.
- Typically this will match the original authorization, but may be more or less.
+ Typically this will match the amount in the original authorization, but can be
+ higher or lower. The sign of this amount will automatically match the sign of
+ the original authorization's amount. For example, entering 100 in this field
+ will result in a -100 amount in the transaction, if the original authorization
+ is a credit authorization.
- If no amount is supplied to this endpoint, the amount of the transaction will be
- captured. Any transaction that has any amount completed at all do not have
- access to this behavior.
+ If `amount` is not set, the full amount of the transaction will be cleared.
+ Transactions that have already cleared, either partially or fully, cannot be
+ cleared again using this endpoint.
"""
diff --git a/src/lithic/types/transaction_simulate_void_params.py b/src/lithic/types/transaction_simulate_void_params.py
index dc796f1f..e5b10ea9 100644
--- a/src/lithic/types/transaction_simulate_void_params.py
+++ b/src/lithic/types/transaction_simulate_void_params.py
@@ -14,7 +14,8 @@ class TransactionSimulateVoidParams(TypedDict, total=False):
amount: int
"""Amount (in cents) to void.
- Typically this will match the original authorization, but may be less.
+ Typically this will match the amount in the original authorization, but can be
+ less.
"""
type: Literal["AUTHORIZATION_EXPIRY", "AUTHORIZATION_REVERSAL"]
From 8125eac6b6bb5e448f8641c362a334f0eab5a5fa Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 26 Nov 2024 15:39:58 +0000
Subject: [PATCH 5/8] chore(api): add backtest methods to AuthRules (#638)
---
.stats.yml | 2 +-
api.md | 29 +-
src/lithic/resources/auth_rules/auth_rules.py | 1 +
.../resources/auth_rules/v2/__init__.py | 33 ++
.../resources/auth_rules/v2/backtests.py | 364 ++++++++++++++++++
.../resources/auth_rules/{ => v2}/v2.py | 66 +++-
src/lithic/types/auth_rules/v2/__init__.py | 7 +
.../auth_rules/v2/backtest_create_params.py | 19 +
.../auth_rules/v2/backtest_create_response.py | 12 +
.../types/auth_rules/v2/backtest_results.py | 114 ++++++
src/lithic/types/settlement_detail.py | 3 +
tests/api_resources/auth_rules/v2/__init__.py | 1 +
.../auth_rules/v2/test_backtests.py | 217 +++++++++++
13 files changed, 842 insertions(+), 26 deletions(-)
create mode 100644 src/lithic/resources/auth_rules/v2/__init__.py
create mode 100644 src/lithic/resources/auth_rules/v2/backtests.py
rename src/lithic/resources/auth_rules/{ => v2}/v2.py (96%)
create mode 100644 src/lithic/types/auth_rules/v2/__init__.py
create mode 100644 src/lithic/types/auth_rules/v2/backtest_create_params.py
create mode 100644 src/lithic/types/auth_rules/v2/backtest_create_response.py
create mode 100644 src/lithic/types/auth_rules/v2/backtest_results.py
create mode 100644 tests/api_resources/auth_rules/v2/__init__.py
create mode 100644 tests/api_resources/auth_rules/v2/test_backtests.py
diff --git a/.stats.yml b/.stats.yml
index 77de7290..8d78762c 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1 +1 @@
-configured_endpoints: 150
+configured_endpoints: 152
diff --git a/api.md b/api.md
index 1305bc6d..9ff4ac64 100644
--- a/api.md
+++ b/api.md
@@ -94,14 +94,27 @@ from lithic.types.auth_rules import (
Methods:
-- client.auth_rules.v2.create(\*\*params) -> V2CreateResponse
-- client.auth_rules.v2.retrieve(auth_rule_token) -> V2RetrieveResponse
-- client.auth_rules.v2.update(auth_rule_token, \*\*params) -> V2UpdateResponse
-- client.auth_rules.v2.list(\*\*params) -> SyncCursorPage[V2ListResponse]
-- client.auth_rules.v2.apply(auth_rule_token, \*\*params) -> V2ApplyResponse
-- 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.create(\*\*params) -> V2CreateResponse
+- client.auth_rules.v2.retrieve(auth_rule_token) -> V2RetrieveResponse
+- client.auth_rules.v2.update(auth_rule_token, \*\*params) -> V2UpdateResponse
+- client.auth_rules.v2.list(\*\*params) -> SyncCursorPage[V2ListResponse]
+- client.auth_rules.v2.apply(auth_rule_token, \*\*params) -> V2ApplyResponse
+- 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
+
+### Backtests
+
+Types:
+
+```python
+from lithic.types.auth_rules.v2 import BacktestResults, BacktestCreateResponse
+```
+
+Methods:
+
+- client.auth_rules.v2.backtests.create(auth_rule_token, \*\*params) -> BacktestCreateResponse
+- client.auth_rules.v2.backtests.retrieve(auth_rule_backtest_token, \*, auth_rule_token) -> BacktestResults
# AuthStreamEnrollment
diff --git a/src/lithic/resources/auth_rules/auth_rules.py b/src/lithic/resources/auth_rules/auth_rules.py
index 387046b5..6ce45ef9 100644
--- a/src/lithic/resources/auth_rules/auth_rules.py
+++ b/src/lithic/resources/auth_rules/auth_rules.py
@@ -10,6 +10,7 @@
V2WithStreamingResponse,
AsyncV2WithStreamingResponse,
)
+from .v2.v2 import V2, AsyncV2
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
diff --git a/src/lithic/resources/auth_rules/v2/__init__.py b/src/lithic/resources/auth_rules/v2/__init__.py
new file mode 100644
index 00000000..aa9d53c0
--- /dev/null
+++ b/src/lithic/resources/auth_rules/v2/__init__.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .v2 import (
+ V2,
+ AsyncV2,
+ V2WithRawResponse,
+ AsyncV2WithRawResponse,
+ V2WithStreamingResponse,
+ AsyncV2WithStreamingResponse,
+)
+from .backtests import (
+ Backtests,
+ AsyncBacktests,
+ BacktestsWithRawResponse,
+ AsyncBacktestsWithRawResponse,
+ BacktestsWithStreamingResponse,
+ AsyncBacktestsWithStreamingResponse,
+)
+
+__all__ = [
+ "Backtests",
+ "AsyncBacktests",
+ "BacktestsWithRawResponse",
+ "AsyncBacktestsWithRawResponse",
+ "BacktestsWithStreamingResponse",
+ "AsyncBacktestsWithStreamingResponse",
+ "V2",
+ "AsyncV2",
+ "V2WithRawResponse",
+ "AsyncV2WithRawResponse",
+ "V2WithStreamingResponse",
+ "AsyncV2WithStreamingResponse",
+]
diff --git a/src/lithic/resources/auth_rules/v2/backtests.py b/src/lithic/resources/auth_rules/v2/backtests.py
new file mode 100644
index 00000000..86584912
--- /dev/null
+++ b/src/lithic/resources/auth_rules/v2/backtests.py
@@ -0,0 +1,364 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from datetime import datetime
+
+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 ...._base_client import make_request_options
+from ....types.auth_rules.v2 import backtest_create_params
+from ....types.auth_rules.v2.backtest_results import BacktestResults
+from ....types.auth_rules.v2.backtest_create_response import BacktestCreateResponse
+
+__all__ = ["Backtests", "AsyncBacktests"]
+
+
+class Backtests(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> BacktestsWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return the
+ 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 BacktestsWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> BacktestsWithStreamingResponse:
+ """
+ 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 BacktestsWithStreamingResponse(self)
+
+ def create(
+ self,
+ auth_rule_token: str,
+ *,
+ end: Union[str, datetime] | NotGiven = NOT_GIVEN,
+ start: Union[str, datetime] | 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,
+ ) -> BacktestCreateResponse:
+ """
+ Initiates a request to asynchronously generate a backtest for an authorization
+ rule. During backtesting, both the active version (if one exists) and the draft
+ version of the Authorization Rule are evaluated by replaying historical
+ transaction data against the rule's conditions. This process allows customers to
+ simulate and understand the effects of proposed rule changes before deployment.
+ The generated backtest report provides detailed results showing whether the
+ draft version of the Auth Rule would have approved or declined historical
+ transactions which were processed during the backtest period. These reports help
+ evaluate how changes to rule configurations might affect overall transaction
+ approval rates.
+
+ The generated backtest report will be delivered asynchronously through a webhook
+ with `event_type` = `auth_rules.backtest_report.created`. See the docs on
+ setting up [webhook subscriptions](https://docs.lithic.com/docs/events-api). It
+ is also possible to request backtest reports on-demand through the
+ `/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.
+
+ Args:
+ end: The end time of the backtest.
+
+ start: The start time of the backtest.
+
+ 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._post(
+ f"/v2/auth_rules/{auth_rule_token}/backtests",
+ body=maybe_transform(
+ {
+ "end": end,
+ "start": start,
+ },
+ backtest_create_params.BacktestCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=BacktestCreateResponse,
+ )
+
+ def retrieve(
+ self,
+ auth_rule_backtest_token: str,
+ *,
+ auth_rule_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,
+ ) -> BacktestResults:
+ """
+ Returns the backtest results of an authorization rule (if available).
+
+ Backtesting is an asynchronous process that requires time to complete. If a
+ customer retrieves the backtest results using this endpoint before the report is
+ fully generated, the response will return null for `results.current_version` and
+ `results.draft_version`. Customers are advised to wait for the backtest creation
+ process to complete (as indicated by the webhook event
+ auth_rules.backtest_report.created) before retrieving results from this
+ endpoint.
+
+ Backtesting is an asynchronous process, while the backtest is being processed,
+ results will not be available which will cause `results.current_version` and
+ `results.draft_version` objects to contain `null`. The entries in `results` will
+ also always represent the configuration of the rule at the time requests are
+ made to this endpoint. For example, the results for `current_version` in the
+ served backtest report will be consistent with which version of the rule is
+ currently activated in the Auth Stream, regardless of which version of the rule
+ was active in the Auth Stream at the time a backtest is requested.
+
+ 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 auth_rule_token:
+ raise ValueError(f"Expected a non-empty value for `auth_rule_token` but received {auth_rule_token!r}")
+ if not auth_rule_backtest_token:
+ raise ValueError(
+ f"Expected a non-empty value for `auth_rule_backtest_token` but received {auth_rule_backtest_token!r}"
+ )
+ return self._get(
+ f"/v2/auth_rules/{auth_rule_token}/backtests/{auth_rule_backtest_token}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=BacktestResults,
+ )
+
+
+class AsyncBacktests(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncBacktestsWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return the
+ 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 AsyncBacktestsWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncBacktestsWithStreamingResponse:
+ """
+ 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 AsyncBacktestsWithStreamingResponse(self)
+
+ async def create(
+ self,
+ auth_rule_token: str,
+ *,
+ end: Union[str, datetime] | NotGiven = NOT_GIVEN,
+ start: Union[str, datetime] | 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,
+ ) -> BacktestCreateResponse:
+ """
+ Initiates a request to asynchronously generate a backtest for an authorization
+ rule. During backtesting, both the active version (if one exists) and the draft
+ version of the Authorization Rule are evaluated by replaying historical
+ transaction data against the rule's conditions. This process allows customers to
+ simulate and understand the effects of proposed rule changes before deployment.
+ The generated backtest report provides detailed results showing whether the
+ draft version of the Auth Rule would have approved or declined historical
+ transactions which were processed during the backtest period. These reports help
+ evaluate how changes to rule configurations might affect overall transaction
+ approval rates.
+
+ The generated backtest report will be delivered asynchronously through a webhook
+ with `event_type` = `auth_rules.backtest_report.created`. See the docs on
+ setting up [webhook subscriptions](https://docs.lithic.com/docs/events-api). It
+ is also possible to request backtest reports on-demand through the
+ `/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.
+
+ Args:
+ end: The end time of the backtest.
+
+ start: The start time of the backtest.
+
+ 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._post(
+ f"/v2/auth_rules/{auth_rule_token}/backtests",
+ body=await async_maybe_transform(
+ {
+ "end": end,
+ "start": start,
+ },
+ backtest_create_params.BacktestCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=BacktestCreateResponse,
+ )
+
+ async def retrieve(
+ self,
+ auth_rule_backtest_token: str,
+ *,
+ auth_rule_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,
+ ) -> BacktestResults:
+ """
+ Returns the backtest results of an authorization rule (if available).
+
+ Backtesting is an asynchronous process that requires time to complete. If a
+ customer retrieves the backtest results using this endpoint before the report is
+ fully generated, the response will return null for `results.current_version` and
+ `results.draft_version`. Customers are advised to wait for the backtest creation
+ process to complete (as indicated by the webhook event
+ auth_rules.backtest_report.created) before retrieving results from this
+ endpoint.
+
+ Backtesting is an asynchronous process, while the backtest is being processed,
+ results will not be available which will cause `results.current_version` and
+ `results.draft_version` objects to contain `null`. The entries in `results` will
+ also always represent the configuration of the rule at the time requests are
+ made to this endpoint. For example, the results for `current_version` in the
+ served backtest report will be consistent with which version of the rule is
+ currently activated in the Auth Stream, regardless of which version of the rule
+ was active in the Auth Stream at the time a backtest is requested.
+
+ 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 auth_rule_token:
+ raise ValueError(f"Expected a non-empty value for `auth_rule_token` but received {auth_rule_token!r}")
+ if not auth_rule_backtest_token:
+ raise ValueError(
+ f"Expected a non-empty value for `auth_rule_backtest_token` but received {auth_rule_backtest_token!r}"
+ )
+ return await self._get(
+ f"/v2/auth_rules/{auth_rule_token}/backtests/{auth_rule_backtest_token}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=BacktestResults,
+ )
+
+
+class BacktestsWithRawResponse:
+ def __init__(self, backtests: Backtests) -> None:
+ self._backtests = backtests
+
+ self.create = _legacy_response.to_raw_response_wrapper(
+ backtests.create,
+ )
+ self.retrieve = _legacy_response.to_raw_response_wrapper(
+ backtests.retrieve,
+ )
+
+
+class AsyncBacktestsWithRawResponse:
+ def __init__(self, backtests: AsyncBacktests) -> None:
+ self._backtests = backtests
+
+ self.create = _legacy_response.async_to_raw_response_wrapper(
+ backtests.create,
+ )
+ self.retrieve = _legacy_response.async_to_raw_response_wrapper(
+ backtests.retrieve,
+ )
+
+
+class BacktestsWithStreamingResponse:
+ def __init__(self, backtests: Backtests) -> None:
+ self._backtests = backtests
+
+ self.create = to_streamed_response_wrapper(
+ backtests.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ backtests.retrieve,
+ )
+
+
+class AsyncBacktestsWithStreamingResponse:
+ def __init__(self, backtests: AsyncBacktests) -> None:
+ self._backtests = backtests
+
+ self.create = async_to_streamed_response_wrapper(
+ backtests.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ backtests.retrieve,
+ )
diff --git a/src/lithic/resources/auth_rules/v2.py b/src/lithic/resources/auth_rules/v2/v2.py
similarity index 96%
rename from src/lithic/resources/auth_rules/v2.py
rename to src/lithic/resources/auth_rules/v2/v2.py
index 72de4301..f0c1fd5e 100644
--- a/src/lithic/resources/auth_rules/v2.py
+++ b/src/lithic/resources/auth_rules/v2/v2.py
@@ -7,32 +7,44 @@
import httpx
-from ... import _legacy_response
-from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
-from ..._utils import (
+from .... import _legacy_response
+from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ...._utils import (
required_args,
maybe_transform,
async_maybe_transform,
)
-from ..._compat import cached_property
-from ..._resource import SyncAPIResource, AsyncAPIResource
-from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
-from ...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.v2_list_response import V2ListResponse
-from ...types.auth_rules.v2_apply_response import V2ApplyResponse
-from ...types.auth_rules.v2_draft_response import V2DraftResponse
-from ...types.auth_rules.v2_create_response import V2CreateResponse
-from ...types.auth_rules.v2_report_response import V2ReportResponse
-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 .backtests import (
+ Backtests,
+ AsyncBacktests,
+ BacktestsWithRawResponse,
+ AsyncBacktestsWithRawResponse,
+ BacktestsWithStreamingResponse,
+ AsyncBacktestsWithStreamingResponse,
+)
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ....pagination import 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.v2_list_response import V2ListResponse
+from ....types.auth_rules.v2_apply_response import V2ApplyResponse
+from ....types.auth_rules.v2_draft_response import V2DraftResponse
+from ....types.auth_rules.v2_create_response import V2CreateResponse
+from ....types.auth_rules.v2_report_response import V2ReportResponse
+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
__all__ = ["V2", "AsyncV2"]
class V2(SyncAPIResource):
+ @cached_property
+ def backtests(self) -> Backtests:
+ return Backtests(self._client)
+
@cached_property
def with_raw_response(self) -> V2WithRawResponse:
"""
@@ -615,6 +627,10 @@ def report(
class AsyncV2(AsyncAPIResource):
+ @cached_property
+ def backtests(self) -> AsyncBacktests:
+ return AsyncBacktests(self._client)
+
@cached_property
def with_raw_response(self) -> AsyncV2WithRawResponse:
"""
@@ -1225,6 +1241,10 @@ def __init__(self, v2: V2) -> None:
v2.report,
)
+ @cached_property
+ def backtests(self) -> BacktestsWithRawResponse:
+ return BacktestsWithRawResponse(self._v2.backtests)
+
class AsyncV2WithRawResponse:
def __init__(self, v2: AsyncV2) -> None:
@@ -1255,6 +1275,10 @@ def __init__(self, v2: AsyncV2) -> None:
v2.report,
)
+ @cached_property
+ def backtests(self) -> AsyncBacktestsWithRawResponse:
+ return AsyncBacktestsWithRawResponse(self._v2.backtests)
+
class V2WithStreamingResponse:
def __init__(self, v2: V2) -> None:
@@ -1285,6 +1309,10 @@ def __init__(self, v2: V2) -> None:
v2.report,
)
+ @cached_property
+ def backtests(self) -> BacktestsWithStreamingResponse:
+ return BacktestsWithStreamingResponse(self._v2.backtests)
+
class AsyncV2WithStreamingResponse:
def __init__(self, v2: AsyncV2) -> None:
@@ -1314,3 +1342,7 @@ def __init__(self, v2: AsyncV2) -> None:
self.report = async_to_streamed_response_wrapper(
v2.report,
)
+
+ @cached_property
+ def backtests(self) -> AsyncBacktestsWithStreamingResponse:
+ return AsyncBacktestsWithStreamingResponse(self._v2.backtests)
diff --git a/src/lithic/types/auth_rules/v2/__init__.py b/src/lithic/types/auth_rules/v2/__init__.py
new file mode 100644
index 00000000..c665d2de
--- /dev/null
+++ b/src/lithic/types/auth_rules/v2/__init__.py
@@ -0,0 +1,7 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .backtest_results import BacktestResults as BacktestResults
+from .backtest_create_params import BacktestCreateParams as BacktestCreateParams
+from .backtest_create_response import BacktestCreateResponse as BacktestCreateResponse
diff --git a/src/lithic/types/auth_rules/v2/backtest_create_params.py b/src/lithic/types/auth_rules/v2/backtest_create_params.py
new file mode 100644
index 00000000..fec2e270
--- /dev/null
+++ b/src/lithic/types/auth_rules/v2/backtest_create_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 datetime
+from typing_extensions import Annotated, TypedDict
+
+from ...._utils import PropertyInfo
+
+__all__ = ["BacktestCreateParams"]
+
+
+class BacktestCreateParams(TypedDict, total=False):
+ end: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]
+ """The end time of the backtest."""
+
+ start: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]
+ """The start time of the backtest."""
diff --git a/src/lithic/types/auth_rules/v2/backtest_create_response.py b/src/lithic/types/auth_rules/v2/backtest_create_response.py
new file mode 100644
index 00000000..28ee75ea
--- /dev/null
+++ b/src/lithic/types/auth_rules/v2/backtest_create_response.py
@@ -0,0 +1,12 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from ...._models import BaseModel
+
+__all__ = ["BacktestCreateResponse"]
+
+
+class BacktestCreateResponse(BaseModel):
+ backtest_token: Optional[str] = None
+ """Auth Rule Backtest Token"""
diff --git a/src/lithic/types/auth_rules/v2/backtest_results.py b/src/lithic/types/auth_rules/v2/backtest_results.py
new file mode 100644
index 00000000..20f6916a
--- /dev/null
+++ b/src/lithic/types/auth_rules/v2/backtest_results.py
@@ -0,0 +1,114 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+
+from ...._models import BaseModel
+
+__all__ = [
+ "BacktestResults",
+ "Results",
+ "ResultsCurrentVersion",
+ "ResultsCurrentVersionExample",
+ "ResultsDraftVersion",
+ "ResultsDraftVersionExample",
+ "SimulationParameters",
+]
+
+
+class ResultsCurrentVersionExample(BaseModel):
+ approved: Optional[bool] = None
+ """Whether the rule would have approved the authorization request."""
+
+ event_token: Optional[str] = None
+ """The authorization request event token."""
+
+ timestamp: Optional[datetime] = None
+ """The timestamp of the authorization request event."""
+
+
+class ResultsCurrentVersion(BaseModel):
+ approved: Optional[int] = None
+ """
+ The total number of historical transactions approved by this rule during the
+ backtest period, or the number of transactions that would have been approved if
+ the rule was evaluated in shadow mode.
+ """
+
+ declined: Optional[int] = None
+ """
+ The total number of historical transactions declined by this rule during the
+ backtest period, or the number of transactions that would have been declined if
+ the rule was evaluated in shadow mode.
+ """
+
+ examples: Optional[List[ResultsCurrentVersionExample]] = None
+ """Example authorization request events that would have been approved or declined."""
+
+ 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 authorization request."""
+
+ event_token: Optional[str] = None
+ """The authorization request event token."""
+
+ timestamp: Optional[datetime] = None
+ """The timestamp of the authorization request event."""
+
+
+class ResultsDraftVersion(BaseModel):
+ approved: Optional[int] = None
+ """
+ The total number of historical transactions approved by this rule during the
+ backtest period, or the number of transactions that would have been approved if
+ the rule was evaluated in shadow mode.
+ """
+
+ declined: Optional[int] = None
+ """
+ The total number of historical transactions declined by this rule during the
+ backtest period, or the number of transactions that would have been declined if
+ the rule was evaluated in shadow mode.
+ """
+
+ examples: Optional[List[ResultsDraftVersionExample]] = None
+ """Example authorization request events that would have been approved or declined."""
+
+ version: Optional[int] = None
+ """
+ The version of the rule, this is incremented whenever the rule's parameters
+ change.
+ """
+
+
+class Results(BaseModel):
+ current_version: Optional[ResultsCurrentVersion] = None
+
+ draft_version: Optional[ResultsDraftVersion] = None
+
+
+class SimulationParameters(BaseModel):
+ auth_rule_token: Optional[str] = None
+ """Auth Rule Token"""
+
+ end: Optional[datetime] = None
+ """The end time of the simulation."""
+
+ start: Optional[datetime] = None
+ """The start time of the simulation."""
+
+
+class BacktestResults(BaseModel):
+ backtest_token: str
+ """Auth Rule Backtest Token"""
+
+ results: Results
+
+ simulation_parameters: SimulationParameters
diff --git a/src/lithic/types/settlement_detail.py b/src/lithic/types/settlement_detail.py
index 975a87e4..c21d9f5e 100644
--- a/src/lithic/types/settlement_detail.py
+++ b/src/lithic/types/settlement_detail.py
@@ -102,3 +102,6 @@ class SettlementDetail(BaseModel):
updated: datetime
"""Date and time when the transaction first occurred. UTC time zone."""
+
+ fee_description: Optional[str] = None
+ """Network's description of a fee, only present on records with type `FEE`."""
diff --git a/tests/api_resources/auth_rules/v2/__init__.py b/tests/api_resources/auth_rules/v2/__init__.py
new file mode 100644
index 00000000..fd8019a9
--- /dev/null
+++ b/tests/api_resources/auth_rules/v2/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/auth_rules/v2/test_backtests.py b/tests/api_resources/auth_rules/v2/test_backtests.py
new file mode 100644
index 00000000..12a05cec
--- /dev/null
+++ b/tests/api_resources/auth_rules/v2/test_backtests.py
@@ -0,0 +1,217 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from lithic import Lithic, AsyncLithic
+from tests.utils import assert_matches_type
+from lithic._utils import parse_datetime
+from lithic.types.auth_rules.v2 import BacktestResults, BacktestCreateResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestBacktests:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: Lithic) -> None:
+ backtest = client.auth_rules.v2.backtests.create(
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(BacktestCreateResponse, backtest, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: Lithic) -> None:
+ backtest = client.auth_rules.v2.backtests.create(
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ end=parse_datetime("2019-12-27T18:11:19.117Z"),
+ start=parse_datetime("2019-12-27T18:11:19.117Z"),
+ )
+ assert_matches_type(BacktestCreateResponse, backtest, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: Lithic) -> None:
+ response = client.auth_rules.v2.backtests.with_raw_response.create(
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ backtest = response.parse()
+ assert_matches_type(BacktestCreateResponse, backtest, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: Lithic) -> None:
+ with client.auth_rules.v2.backtests.with_streaming_response.create(
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ backtest = response.parse()
+ assert_matches_type(BacktestCreateResponse, backtest, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_create(self, client: Lithic) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `auth_rule_token` but received ''"):
+ client.auth_rules.v2.backtests.with_raw_response.create(
+ auth_rule_token="",
+ )
+
+ @parametrize
+ def test_method_retrieve(self, client: Lithic) -> None:
+ backtest = client.auth_rules.v2.backtests.retrieve(
+ auth_rule_backtest_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(BacktestResults, backtest, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Lithic) -> None:
+ response = client.auth_rules.v2.backtests.with_raw_response.retrieve(
+ auth_rule_backtest_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ backtest = response.parse()
+ assert_matches_type(BacktestResults, backtest, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Lithic) -> None:
+ with client.auth_rules.v2.backtests.with_streaming_response.retrieve(
+ auth_rule_backtest_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ backtest = response.parse()
+ assert_matches_type(BacktestResults, backtest, 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 `auth_rule_token` but received ''"):
+ client.auth_rules.v2.backtests.with_raw_response.retrieve(
+ auth_rule_backtest_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ auth_rule_token="",
+ )
+
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `auth_rule_backtest_token` but received ''"
+ ):
+ client.auth_rules.v2.backtests.with_raw_response.retrieve(
+ auth_rule_backtest_token="",
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+
+class TestAsyncBacktests:
+ parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ async def test_method_create(self, async_client: AsyncLithic) -> None:
+ backtest = await async_client.auth_rules.v2.backtests.create(
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(BacktestCreateResponse, backtest, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncLithic) -> None:
+ backtest = await async_client.auth_rules.v2.backtests.create(
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ end=parse_datetime("2019-12-27T18:11:19.117Z"),
+ start=parse_datetime("2019-12-27T18:11:19.117Z"),
+ )
+ assert_matches_type(BacktestCreateResponse, backtest, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncLithic) -> None:
+ response = await async_client.auth_rules.v2.backtests.with_raw_response.create(
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ backtest = response.parse()
+ assert_matches_type(BacktestCreateResponse, backtest, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncLithic) -> None:
+ async with async_client.auth_rules.v2.backtests.with_streaming_response.create(
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ backtest = await response.parse()
+ assert_matches_type(BacktestCreateResponse, backtest, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_create(self, async_client: AsyncLithic) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `auth_rule_token` but received ''"):
+ await async_client.auth_rules.v2.backtests.with_raw_response.create(
+ auth_rule_token="",
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncLithic) -> None:
+ backtest = await async_client.auth_rules.v2.backtests.retrieve(
+ auth_rule_backtest_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(BacktestResults, backtest, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncLithic) -> None:
+ response = await async_client.auth_rules.v2.backtests.with_raw_response.retrieve(
+ auth_rule_backtest_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ backtest = response.parse()
+ assert_matches_type(BacktestResults, backtest, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncLithic) -> None:
+ async with async_client.auth_rules.v2.backtests.with_streaming_response.retrieve(
+ auth_rule_backtest_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ backtest = await response.parse()
+ assert_matches_type(BacktestResults, backtest, 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 `auth_rule_token` but received ''"):
+ await async_client.auth_rules.v2.backtests.with_raw_response.retrieve(
+ auth_rule_backtest_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ auth_rule_token="",
+ )
+
+ with pytest.raises(
+ ValueError, match=r"Expected a non-empty value for `auth_rule_backtest_token` but received ''"
+ ):
+ await async_client.auth_rules.v2.backtests.with_raw_response.retrieve(
+ auth_rule_backtest_token="",
+ auth_rule_token="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
From 9ad6f0bbf8ffc74641f018adaa1cc99e80be1d12 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 27 Nov 2024 14:03:56 +0000
Subject: [PATCH 6/8] chore(internal): exclude mypy from running on tests
(#639)
---
mypy.ini | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/mypy.ini b/mypy.ini
index 1058d865..b21574d7 100644
--- a/mypy.ini
+++ b/mypy.ini
@@ -5,7 +5,10 @@ show_error_codes = True
# Exclude _files.py because mypy isn't smart enough to apply
# the correct type narrowing and as this is an internal module
# it's fine to just use Pyright.
-exclude = ^(src/lithic/_files\.py|_dev/.*\.py|src/lithic/resources/external_bank_accounts/external_bank_accounts\.py)$
+#
+# We also exclude our `tests` as mypy doesn't always infer
+# types correctly and Pyright will still catch any type errors.
+exclude = ^(src/lithic/_files\.py|_dev/.*\.py|tests/.*|src/lithic/resources/external_bank_accounts/external_bank_accounts\.py)$
strict_equality = True
implicit_reexport = True
From ec6c6fdfd8e4182339790ffd54dadb2d0dbe69f1 Mon Sep 17 00:00:00 2001
From: Samuel El-Borai
Date: Thu, 28 Nov 2024 14:29:00 +0100
Subject: [PATCH 7/8] trigger CI
From bfb50648051f9798c451a1e00c2d2cc82ca32c36 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 28 Nov 2024 13:29:20 +0000
Subject: [PATCH 8/8] release: 0.80.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 21 +++++++++++++++++++++
pyproject.toml | 2 +-
src/lithic/_version.py | 2 +-
4 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 29fa70ce..c3e137b1 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.79.1"
+ ".": "0.80.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a3404721..aa845052 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,26 @@
# Changelog
+## 0.80.0 (2024-11-28)
+
+Full Changelog: [v0.79.1...v0.80.0](https://github.com/lithic-com/lithic-python/compare/v0.79.1...v0.80.0)
+
+### Features
+
+* **api:** updates to Auth Rules numeric types, new Card Types and Authorization Rule Backtests ([#637](https://github.com/lithic-com/lithic-python/issues/637)) ([6436634](https://github.com/lithic-com/lithic-python/commit/6436634a1a0ccc9b6ec070c2553bdb45ab656dd6))
+
+
+### Chores
+
+* **api:** add backtest methods to AuthRules ([#638](https://github.com/lithic-com/lithic-python/issues/638)) ([8125eac](https://github.com/lithic-com/lithic-python/commit/8125eac6b6bb5e448f8641c362a334f0eab5a5fa))
+* **internal:** exclude mypy from running on tests ([#639](https://github.com/lithic-com/lithic-python/issues/639)) ([9ad6f0b](https://github.com/lithic-com/lithic-python/commit/9ad6f0bbf8ffc74641f018adaa1cc99e80be1d12))
+* **internal:** fix compat model_dump method when warnings are passed ([#633](https://github.com/lithic-com/lithic-python/issues/633)) ([eb6c135](https://github.com/lithic-com/lithic-python/commit/eb6c135106a0e11e15aa6245db72a019ea90668e))
+* remove now unused `cached-property` dep ([#636](https://github.com/lithic-com/lithic-python/issues/636)) ([78321ef](https://github.com/lithic-com/lithic-python/commit/78321efbac2e6da20afb852d6bf38fa371751d99))
+
+
+### Documentation
+
+* add info log level to readme ([#635](https://github.com/lithic-com/lithic-python/issues/635)) ([aed46f6](https://github.com/lithic-com/lithic-python/commit/aed46f67456c19cf389275607f593e8e269e3237))
+
## 0.79.1 (2024-11-18)
Full Changelog: [v0.79.0...v0.79.1](https://github.com/lithic-com/lithic-python/compare/v0.79.0...v0.79.1)
diff --git a/pyproject.toml b/pyproject.toml
index ed9ddfff..4ad7297d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "lithic"
-version = "0.79.1"
+version = "0.80.0"
description = "The official Python library for the lithic API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/lithic/_version.py b/src/lithic/_version.py
index d7e9daf8..18af888f 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.79.1" # x-release-please-version
+__version__ = "0.80.0" # x-release-please-version