From 318cdd271252af9cfa7bca504c8cc3c98b473051 Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Wed, 13 Dec 2023 15:06:20 -0500 Subject: [PATCH 01/32] removed deprecated connections. Added credit_scores endpoint --- README.md | 19 ------------ method/method.py | 3 -- method/resources/Connection.py | 53 ---------------------------------- method/resources/Entity.py | 40 +++++++++++++++++++++++++ method/resources/__init__.py | 1 - 5 files changed, 40 insertions(+), 76 deletions(-) delete mode 100644 method/resources/Connection.py diff --git a/README.md b/README.md index a71e867..6e9cee1 100644 --- a/README.md +++ b/README.md @@ -419,22 +419,3 @@ report = method.reports.get('rpt_cj2mkA3hFyHT5') report_csv = method.reports.download('rpt_cj2mkA3hFyHT5') ``` -## Connections - -### List Connections - -```python -connections = method.connections.list() -``` - -### Retrieve Connection - -```python -connection = method.connections.get('cxn_iENwAPKnNqA5j') -``` - -### Update Connection - -```python -connection = method.connections.update('cxn_iENwAPKnNqA5j', { 'status': 'syncing' }) -``` diff --git a/method/method.py b/method/method.py index c585009..5613d67 100644 --- a/method/method.py +++ b/method/method.py @@ -9,7 +9,6 @@ from method.resources.RoutingNumber import RoutingNumberResource from method.resources.Webhook import WebhookResource from method.resources.HealthCheck import PingResponse, HealthCheckResource -from method.resources.Connection import ConnectionResource from method.resources.Simulate import SimulateResource @@ -24,7 +23,6 @@ class Method: routing_numbers: RoutingNumberResource webhooks: WebhookResource healthcheck: HealthCheckResource - connections: ConnectionResource simulate: SimulateResource def __init__(self, opts: ConfigurationOpts = None, **kwargs: ConfigurationOpts): @@ -41,7 +39,6 @@ def __init__(self, opts: ConfigurationOpts = None, **kwargs: ConfigurationOpts): self.routing_numbers = RoutingNumberResource(config) self.webhooks = WebhookResource(config) self.healthcheck = HealthCheckResource(config) - self.connections = ConnectionResource(config) self.simulate = SimulateResource(config) def ping(self) -> PingResponse: diff --git a/method/resources/Connection.py b/method/resources/Connection.py deleted file mode 100644 index 40eb607..0000000 --- a/method/resources/Connection.py +++ /dev/null @@ -1,53 +0,0 @@ -from typing import TypedDict, Optional, List, Dict, Any, Literal - -from method.resources import Account -from method.errors import ResourceError -from method.resource import Resource -from method.configuration import Configuration - - -ConnectionSourcesLiterals = Literal[ - 'plaid', - 'mch_5500' -] - - -ConnectionStatusesLiterals = Literal[ - 'success', - 'reauth_required', - 'syncing', - 'failed' -] - - -class Connection(TypedDict): - id: str - entity_id: str - accounts: List[str] - source: ConnectionSourcesLiterals - status: ConnectionStatusesLiterals - error: Optional[ResourceError] - created_at: str - updated_at: str - last_synced_at: str - - -class ConnectionUpdateOpts(TypedDict): - status: Literal['syncing'] - - -class ConnectionResource(Resource): - def __init__(self, config: Configuration): - super(ConnectionResource, self).__init__(config.add_path('connections')) - - def get(self, _id: str) -> Connection: - return super(ConnectionResource, self)._get_with_id(_id) - - def list(self) -> List[Connection]: - return super(ConnectionResource, self)._list(None) - - def update(self, _id: str, opts: ConnectionUpdateOpts) -> Connection: - return super(ConnectionResource, self)._update_with_id(_id, opts) - - def get_public_account_tokens(self, _id: str) -> List[str]: - return super(ConnectionResource, self)._get_with_sub_path('{_id}/public_account_tokens'.format(_id=_id)) diff --git a/method/resources/Entity.py b/method/resources/Entity.py index 7ab5023..2ec1593 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -31,6 +31,21 @@ ] +CreditScoreStatusesLiterals = Literal[ + 'completed', + 'in_progress', + 'pending', + 'failed' +] + + +CreditReportBureausLiterals = Literal[ + 'experian', + 'equifax', + 'transunion' +] + + class EntityIndividual(TypedDict): first_name: Optional[str] last_name: Optional[str] @@ -126,6 +141,25 @@ class EntityGetCreditScoreResponse(TypedDict): score: int updated_at: str +class EntityCreditScoresFactorsType(TypedDict): + code: str + description: str + +class EntityCreditScoresType(TypedDict): + score: int + source: CreditReportBureausLiterals + model: str + factors: EntityCreditScoresFactorsType + created_at: str + +class EntityCreditScoresResponse(TypedDict): + id: str + status: EntityStatusesLiterals + credit_scores: Optional[List[EntityCreditScoresType]] + error: Optional[ResourceError] + created_at: str + updated_at: str + class AnswerOpts(TypedDict): question_id: str answer_id: str @@ -159,6 +193,12 @@ def create_auth_session(self, _id: str) -> EntityQuestionResponse: def get_credit_score(self, _id: str) -> EntityQuestionResponse: return super(EntityResource, self)._get_with_sub_path('{_id}/credit_score'.format(_id=_id)) + + def get_credit_scores(self, _id: str, crs_id: str) -> EntityCreditScoresResponse: + return super(EntityResource, self)._get_with_sub_path('{_id}/credit_scores/{crs_id}'.format(_id=_id, crs_id=crs_id)) + + def create_credit_scores(self, _id: str) -> EntityCreditScoresResponse: + return super(EntityResource, self)._create_with_sub_path('{_id}/credit_scores'.format(_id=_id), {}) def update_auth_session(self, _id: str, opts: EntityUpdateAuthOpts) -> EntityUpdateAuthResponse: return super(EntityResource, self)._update_with_sub_path('{_id}/auth_session'.format(_id=_id), opts) diff --git a/method/resources/__init__.py b/method/resources/__init__.py index 60e05da..35d0caa 100644 --- a/method/resources/__init__.py +++ b/method/resources/__init__.py @@ -11,5 +11,4 @@ from method.resources.Verification import Verification, VerificationResource from method.resources.Webhook import Webhook, WebhookResource from method.resources.HealthCheck import HealthCheckResource -from method.resources.Connection import ConnectionResource from method.resources.Simulate import SimulatePaymentResource From 0c5d10c3aace87c651693630c97c7089d0fcc2d6 Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Wed, 13 Dec 2023 15:08:50 -0500 Subject: [PATCH 02/32] fixed factors type in EntityCreditScoresType --- method/resources/Entity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/method/resources/Entity.py b/method/resources/Entity.py index 2ec1593..e672d22 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -149,7 +149,7 @@ class EntityCreditScoresType(TypedDict): score: int source: CreditReportBureausLiterals model: str - factors: EntityCreditScoresFactorsType + factors: List[EntityCreditScoresFactorsType] created_at: str class EntityCreditScoresResponse(TypedDict): From 6879e4e12ec942a0dc9526350d87bffc7759fafe Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Thu, 14 Dec 2023 13:16:55 -0500 Subject: [PATCH 03/32] updated version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2f9f60a..fc24aaa 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='method-python', - version='0.0.31', + version='0.0.32', description='Python library for the Method API', long_description='Python library for the Method API', long_description_content_type='text/x-rst', From ef1bfe8839b548cb5760b679191413ba889474e8 Mon Sep 17 00:00:00 2001 From: stephenluc Date: Fri, 8 Sep 2023 21:17:20 -0500 Subject: [PATCH 04/32] update merchants --- method/resources/Entity.py | 10 ++++++++++ method/resources/Merchant.py | 14 ++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/method/resources/Entity.py b/method/resources/Entity.py index e672d22..e7ff567 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -191,6 +191,7 @@ def list(self, params: EntityListOpts = None) -> List[Entity]: def create_auth_session(self, _id: str) -> EntityQuestionResponse: return super(EntityResource, self)._create_with_sub_path('{_id}/auth_session'.format(_id=_id), {}) +<<<<<<< HEAD def get_credit_score(self, _id: str) -> EntityQuestionResponse: return super(EntityResource, self)._get_with_sub_path('{_id}/credit_score'.format(_id=_id)) @@ -200,12 +201,21 @@ def get_credit_scores(self, _id: str, crs_id: str) -> EntityCreditScoresResponse def create_credit_scores(self, _id: str) -> EntityCreditScoresResponse: return super(EntityResource, self)._create_with_sub_path('{_id}/credit_scores'.format(_id=_id), {}) +======= +>>>>>>> 6276590 (update merchants) def update_auth_session(self, _id: str, opts: EntityUpdateAuthOpts) -> EntityUpdateAuthResponse: return super(EntityResource, self)._update_with_sub_path('{_id}/auth_session'.format(_id=_id), opts) + # TODO: Add create and update manual auth session + def refresh_capabilities(self, _id: str) -> Entity: return super(EntityResource, self)._create_with_sub_path('{_id}/refresh_capabilities'.format(_id=_id), {}) + def get_credit_score(self, _id: str) -> EntityQuestionResponse: + return super(EntityResource, self)._get_with_sub_path('{_id}/credit_score'.format(_id=_id)) + + # TODO: get sensitive fields + def withdraw_consent(self, _id: str) -> Entity: return super(EntityResource, self)._create_with_sub_path( '{_id}/consent'.format(_id=_id), diff --git a/method/resources/Merchant.py b/method/resources/Merchant.py index 47b7c76..e08f5be 100644 --- a/method/resources/Merchant.py +++ b/method/resources/Merchant.py @@ -23,7 +23,9 @@ 'home_equity_loan', 'mortgage', 'utility', - 'waste_utility' + 'waste_utility', + 'collection' + 'credit_builder', ] @@ -43,14 +45,14 @@ class Merchant(TypedDict): types: List[MerchantTypesLiterals] account_prefixes: List[str] provider_ids: MerchantProviderIds - + customized_auth: bool + is_temp: bool class MerchantListOpts(TypedDict): name: Optional[str] - limit: Optional[int] - # 'provider_id.plaid': Optional[str] - # 'provider_id.mx': Optional[str] - # 'provider_id.finicity': Optional[str] + 'provider_id.plaid': Optional[str] + 'provider_id.mx': Optional[str] + 'provider_id.finicity': Optional[str] class MerchantResource(Resource): From 635201cf2d8f60a5f862efb595f6d08b7124d255 Mon Sep 17 00:00:00 2001 From: stephenluc Date: Fri, 8 Sep 2023 21:52:46 -0500 Subject: [PATCH 05/32] Add transactions --- method/method.py | 3 ++ method/resources/AccountSync.py | 2 +- method/resources/Connection.py | 53 +++++++++++++++++++++++++++++++++ method/resources/Entity.py | 3 -- method/resources/HealthCheck.py | 2 +- method/resources/Reversal.py | 2 +- method/resources/Transaction.py | 30 +++++++++++++++++++ method/resources/__init__.py | 1 + 8 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 method/resources/Connection.py create mode 100644 method/resources/Transaction.py diff --git a/method/method.py b/method/method.py index 5613d67..8abe147 100644 --- a/method/method.py +++ b/method/method.py @@ -10,6 +10,7 @@ from method.resources.Webhook import WebhookResource from method.resources.HealthCheck import PingResponse, HealthCheckResource from method.resources.Simulate import SimulateResource +from method.resources.Transaction import TransactionResource class Method: @@ -24,6 +25,7 @@ class Method: webhooks: WebhookResource healthcheck: HealthCheckResource simulate: SimulateResource + transaction: TransactionResource def __init__(self, opts: ConfigurationOpts = None, **kwargs: ConfigurationOpts): _opts: ConfigurationOpts = {**(opts or {}), **kwargs} # type: ignore @@ -40,6 +42,7 @@ def __init__(self, opts: ConfigurationOpts = None, **kwargs: ConfigurationOpts): self.webhooks = WebhookResource(config) self.healthcheck = HealthCheckResource(config) self.simulate = SimulateResource(config) + self.transaction = TransactionResource(config) def ping(self) -> PingResponse: return self.healthcheck.get() diff --git a/method/resources/AccountSync.py b/method/resources/AccountSync.py index 18d12ed..d528bce 100644 --- a/method/resources/AccountSync.py +++ b/method/resources/AccountSync.py @@ -1,4 +1,4 @@ -from typing import TypedDict, Optional, Dict, List, Any, Literal +from typing import TypedDict, Optional from method.resource import Resource, RequestOpts from method.configuration import Configuration diff --git a/method/resources/Connection.py b/method/resources/Connection.py new file mode 100644 index 0000000..c38f67b --- /dev/null +++ b/method/resources/Connection.py @@ -0,0 +1,53 @@ +from typing import TypedDict, Optional, List, Literal + +from method.resources import Account +from method.errors import ResourceError +from method.resource import Resource +from method.configuration import Configuration + + +ConnectionSourcesLiterals = Literal[ + 'plaid', + 'mch_5500' +] + + +ConnectionStatusesLiterals = Literal[ + 'success', + 'reauth_required', + 'syncing', + 'failed' +] + + +class Connection(TypedDict): + id: str + entity_id: str + accounts: List[str] + source: ConnectionSourcesLiterals + status: ConnectionStatusesLiterals + error: Optional[ResourceError] + created_at: str + updated_at: str + last_synced_at: str + + +class ConnectionUpdateOpts(TypedDict): + status: Literal['syncing'] + + +class ConnectionResource(Resource): + def __init__(self, config: Configuration): + super(ConnectionResource, self).__init__(config.add_path('connections')) + + def get(self, _id: str) -> Connection: + return super(ConnectionResource, self)._get_with_id(_id) + + def list(self) -> List[Connection]: + return super(ConnectionResource, self)._list(None) + + def update(self, _id: str, opts: ConnectionUpdateOpts) -> Connection: + return super(ConnectionResource, self)._update_with_id(_id, opts) + + def get_public_account_tokens(self, _id: str) -> List[str]: + return super(ConnectionResource, self)._get_with_sub_path('{_id}/public_account_tokens'.format(_id=_id)) diff --git a/method/resources/Entity.py b/method/resources/Entity.py index e7ff567..ce888e3 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -191,7 +191,6 @@ def list(self, params: EntityListOpts = None) -> List[Entity]: def create_auth_session(self, _id: str) -> EntityQuestionResponse: return super(EntityResource, self)._create_with_sub_path('{_id}/auth_session'.format(_id=_id), {}) -<<<<<<< HEAD def get_credit_score(self, _id: str) -> EntityQuestionResponse: return super(EntityResource, self)._get_with_sub_path('{_id}/credit_score'.format(_id=_id)) @@ -201,8 +200,6 @@ def get_credit_scores(self, _id: str, crs_id: str) -> EntityCreditScoresResponse def create_credit_scores(self, _id: str) -> EntityCreditScoresResponse: return super(EntityResource, self)._create_with_sub_path('{_id}/credit_scores'.format(_id=_id), {}) -======= ->>>>>>> 6276590 (update merchants) def update_auth_session(self, _id: str, opts: EntityUpdateAuthOpts) -> EntityUpdateAuthResponse: return super(EntityResource, self)._update_with_sub_path('{_id}/auth_session'.format(_id=_id), opts) diff --git a/method/resources/HealthCheck.py b/method/resources/HealthCheck.py index e44c2f6..1388410 100644 --- a/method/resources/HealthCheck.py +++ b/method/resources/HealthCheck.py @@ -1,4 +1,4 @@ -from typing import Any, TypedDict, Literal +from typing import TypedDict, Literal from method.resource import Resource from method.configuration import Configuration diff --git a/method/resources/Reversal.py b/method/resources/Reversal.py index 561a63a..ae4deff 100644 --- a/method/resources/Reversal.py +++ b/method/resources/Reversal.py @@ -1,4 +1,4 @@ -from typing import TypedDict, List, Literal, Dict, Any, Optional +from typing import TypedDict, List, Literal, Optional from method.resource import Resource from method.configuration import Configuration diff --git a/method/resources/Transaction.py b/method/resources/Transaction.py new file mode 100644 index 0000000..85170e1 --- /dev/null +++ b/method/resources/Transaction.py @@ -0,0 +1,30 @@ +from typing import TypedDict, List + +from method.resource import Resource +from method.configuration import Configuration + + +class Transaction(TypedDict): + id: str + acc_id: str + mcc: str + description: str + presentable_description: str + amount: str + currency: str + billing_amount: str + billing_currency: str + status: str + created_at: str + updated_at: str + + +class TransactionResource(Resource): + def __init__(self, config: Configuration): + super(TransactionResource, self).__init__(config.add_path('resource')) + + def list(self) -> List[Transaction]: + return super(TransactionResource, self)._list(None) + + def get(self, _id: str) -> Transaction: + return super(TransactionResource, self)._get_with_id(_id) diff --git a/method/resources/__init__.py b/method/resources/__init__.py index 35d0caa..01ae365 100644 --- a/method/resources/__init__.py +++ b/method/resources/__init__.py @@ -12,3 +12,4 @@ from method.resources.Webhook import Webhook, WebhookResource from method.resources.HealthCheck import HealthCheckResource from method.resources.Simulate import SimulatePaymentResource +from method.resources.Transaction import TransactionResource From d9348383ed64e73f69f7f8742a3239376f33bf28 Mon Sep 17 00:00:00 2001 From: stephenluc Date: Tue, 12 Sep 2023 18:32:04 -0400 Subject: [PATCH 06/32] update entities --- method/resources/Entity.py | 59 +++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/method/resources/Entity.py b/method/resources/Entity.py index ce888e3..fabe4ec 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -39,6 +39,14 @@ ] +EntityIndividualPhoneVerificationTypesLiterals = Literal[ + 'method_sms', + 'method_verified', + 'sms', + 'tos' +] + + CreditReportBureausLiterals = Literal[ 'experian', 'equifax', @@ -125,21 +133,24 @@ class EntityListOpts(TypedDict): status: Optional[str] type: Optional[str] + class EntityAnswer(TypedDict): id: str text: str + class EntityQuestion(TypedDict): id: str text: Optional[str] answers: List[EntityAnswer] + class EntityQuestionResponse(TypedDict): questions: List[EntityQuestion] + authenticated: bool + cxn_id: List[str] + accounts: List[str] -class EntityGetCreditScoreResponse(TypedDict): - score: int - updated_at: str class EntityCreditScoresFactorsType(TypedDict): code: str @@ -164,12 +175,46 @@ class AnswerOpts(TypedDict): question_id: str answer_id: str + class EntityUpdateAuthOpts(TypedDict): - answers: List[AnswerOpts] + answers: List[AnswerOpts] + class EntityUpdateAuthResponse(TypedDict): - questions: List[EntityQuestion] - cxn_id: Optional[str] + questions: List[EntityQuestion] + authenticated: bool + cxn_id: Optional[str] + accounts: List[str] + + +class EntityManualAuthOpts(TypedDict): + format: str + bureau: CreditReportBureausLiterals + raw_report: Dict[str, Any] + + +class EntityManualAuthResponse(TypedDict): + authenticated: bool + accounts: List[str] + + +class EntityGetCreditScoreResponse(TypedDict): + score: int + updated_at: str + + +class AnswerOpts(TypedDict): + question_id: str + answer_id: str + + +class EntityUpdateAuthOpts(TypedDict): + answers: List[AnswerOpts] + + +class EntityUpdateAuthResponse(TypedDict): + questions: List[EntityQuestion] + cxn_id: Optional[str] class EntityResource(Resource): @@ -216,5 +261,5 @@ def get_credit_score(self, _id: str) -> EntityQuestionResponse: def withdraw_consent(self, _id: str) -> Entity: return super(EntityResource, self)._create_with_sub_path( '{_id}/consent'.format(_id=_id), - { 'type': 'withdraw', 'reason': 'entity_withdrew_consent' } + {'type': 'withdraw', 'reason': 'entity_withdrew_consent'} ) From 887df97069f2da7b70a88f6b3e3164459dab4edc Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Wed, 20 Dec 2023 12:11:42 -0500 Subject: [PATCH 07/32] removed connections from README --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 6e9cee1..bc68c12 100644 --- a/README.md +++ b/README.md @@ -417,5 +417,4 @@ report = method.reports.get('rpt_cj2mkA3hFyHT5') ```python report_csv = method.reports.download('rpt_cj2mkA3hFyHT5') -``` - +``` \ No newline at end of file From 9ed4f2743522b142e4c7f95e7a6acf1e91d0cf0c Mon Sep 17 00:00:00 2001 From: stephenluc Date: Fri, 8 Sep 2023 20:51:40 -0500 Subject: [PATCH 08/32] Update accounts --- method/resources/Account.py | 441 +++++++++++++++++++++++++++++------- 1 file changed, 353 insertions(+), 88 deletions(-) diff --git a/method/resources/Account.py b/method/resources/Account.py index 68afda0..393ed33 100644 --- a/method/resources/Account.py +++ b/method/resources/Account.py @@ -1,29 +1,69 @@ -from typing import TypedDict, Optional, Dict, List, Any, Literal +from typing import TypedDict, Optional, Dict, List, Any, Literal, Union from method.resource import Resource, RequestOpts from method.configuration import Configuration from method.errors import ResourceError from method.resources.Verification import VerificationResource -from method.resources.AccountSync import AccountSyncResource +from method.resources.AccountSync import AccountSyncResource, AccountSync -AccountTypesLiterals = Literal[ - 'ach', - 'liability', - 'clearing' +# Literals, keep ordered alphabetically +AccountCapabilitiesLiterals = Literal[ + 'payments:receive', + 'payments:send', + 'data:retrieve', + 'data:sync' ] -AccountSubTypes = Literal[ - 'checking', - 'savings' +AccountClearingSubTypesLiterals = Literal[ + 'single_use' ] -AccountCapabilitiesLiterals = Literal[ - 'payments:receive', - 'payments:send', - 'data:retrieve' +AccountLiabilityDataSourcesLiterls = Literal[ + 'credit_report', + 'financial_institution', + 'unavailable' +] + + +AccountLiabilityDataStatusesLiterals = Literal[ + 'active', + 'syncing', + 'unavailable', + 'failed', + 'pending' +] + + +AccountLiabilityPaymentStatuesLiterals = Literal[ + 'active', + 'activating', + 'unavailable' +] + + +AccountLiabilitySyncTypesLiterals = Literal[ + 'manual', + 'auto' +] + + +AccountLiabilityTypesLiterals = Literal[ + 'student_loan', + 'credit_card', + 'mortgage', + 'auto_loan', + 'collection', + 'personal_loan', + 'business_loan', + 'insurance', + 'credit_builder', + 'subscription', + 'utility', + 'medical', + 'loan' ] @@ -34,23 +74,197 @@ 'processing' ] -AccountDetailTypesLiterals = Literal[ - 'bnpl_loan', - 'depository', - 'credit_card', - 'student_loan' + +AccountSubTypesLiterals = Literal[ + 'checking', + 'savings' ] +AccountTypesLiterals = Literal[ + 'ach', + 'liability', + 'clearing' +] + +AutoPayStatusesLiterals = Literal[ + 'unknown', + 'active', + 'inactive' +] + + +TradelineAccountOwnershipLiterals = Literal[ + 'primary', + 'authorized', + 'joint', + 'unknown' +] + + +PastDueStatusesLiterals = Literal[ + 'unknown', + 'overdue', + 'on_time' +] + + +# Typed Classes class AccountACH(TypedDict): routing: int number: int - type: AccountSubTypes + type: AccountSubTypesLiterals + + +class AccountLiabilityLoan(TypedDict): + name: str + balance: Optional[int] + opened_at: Optional[str] + original_loan_amount: Optional[int] + sub_type: Optional[str] + term_length: Optional[int] + closed_at: Optional[str] + last_payment_amount: Optional[int] + last_payment_date: Optional[str] + next_payment_minimum_amount: Optional[int] + next_payment_due_date: Optional[str] + interest_rate_type: Literal['fixed', 'variable'] + interest_rate_percentage: Optional[int] + interest_rate_source: Optional[Literal['financial_institution', 'public_data', 'method']] + + +class AccountLiabilityCreditCard(AccountLiabilityLoan): + last_statement_balance: Optional[int] + remaining_statement_balance: Optional[int] + available_credit: Optional[int] + auto_pay_status: Optional[AutoPayStatusesLiterals] + auto_pay_amount: Optional[int] + auto_pay_date: Optional[str] + past_due_status: Optional[PastDueStatusesLiterals] + past_due_balance: Optional[int] + past_due_date: Optional[str] + credit_limit: Optional[int] + pending_purchase_authorization_amount: Optional[int] + pending_credit_authorization_amount: Optional[int] + interest_saving_balance: Optional[int] + next_statement_date: Optional[str] + + +class AccountLiabilityAutoLoan(AccountLiabilityLoan): + sub_type: Optional[Literal['lease', 'loan']] + payoff_amount: Optional[int] + payoff_amount_term: Optional[int] + past_due_status: Optional[PastDueStatusesLiterals] + past_due_balance: Optional[int] + past_due_date: Optional[str] + late_fees_amount: Optional[int] + expected_payoff_date: Optional[str] + principal_balance: Optional[int] + per_diem_amount: Optional[int] + mileage_allocation: Optional[int] + + +class AccountLiabilityStudentLoan(AccountLiabilityLoan): + sub_type: Optional[Literal['federal', 'private']] + sequence: Optional[int] + disbursed_at: Optional[str] + expected_payoff_date: Optional[str] + payoff_amount: Optional[int] + payoff_amount_term: Optional[int] + principal_balance: Optional[int] + + +class AccountLiabilityMortgage(AccountLiabilityLoan): + principal_balance: Optional[int] + expected_payoff_date: Optional[str] + address_street: Optional[str] + address_city: Optional[str] + address_state: Optional[str] + address_zip: Optional[str] + property_value: Optional[int] + past_due_status: Optional[PastDueStatusesLiterals] + past_due_balance: Optional[int] + past_due_date: Optional[str] + payoff_amount: Optional[int] + payoff_amount_term: Optional[int] + year_to_date_interest_paid: Optional[int] + year_to_date_principal_paid: Optional[int] + year_to_date_taxes_paid: Optional[int] + year_start_principal_balance: Optional[int] + escrow_balance: Optional[int] + + +class AccountLiabilityPersonalLoan(AccountLiabilityLoan): + expected_payoff_date: Optional[str] + available_credit: Optional[int] + principal_balance: Optional[int] + year_to_date_interest_paid: Optional[int] + + +class AccountLiabilityCreditBuilder(AccountLiabilityLoan): + pass + + +class AccountLiabilityCollection(AccountLiabilityLoan): + pass + + +class AccountLiabilityBusinessLoan(TypedDict): + name: str + balance: Optional[int] + opened_at: Optional[str] + + +class AccountLiabilityInsurance(TypedDict): + name: str + balance: Optional[int] + opened_at: Optional[str] + + +class AccountLiabilitySubscription(TypedDict): + name: str + balance: Optional[int] + opened_at: Optional[str] + + +class AccountLiabilityUtility(TypedDict): + name: str + balance: Optional[int] + opened_at: Optional[str] + + +class AccountLiabilityMedical(TypedDict): + name: str + balance: Optional[int] + opened_at: Optional[str] class AccountLiability(TypedDict): mch_id: str mask: str + payment_status: AccountLiabilityPaymentStatuesLiterals + data_status: AccountLiabilityDataStatusesLiterals + data_last_successful_sync: Optional[str] + data_status_error: Optional[ResourceError] + data_source: AccountLiabilityDataSourcesLiterls + data_updated_at: Optional[str] + data_sync_type: AccountLiabilitySyncTypesLiterals + ownership: TradelineAccountOwnershipLiterals + hash: str + type: AccountLiabilityTypesLiterals + loan: Optional[AccountLiabilityLoan] + student_loan: Optional[AccountLiabilityStudentLoan] + credit_card: Optional[AccountLiabilityCreditCard] + mortgage: Optional[AccountLiabilityMortgage] + auto_loan: Optional[AccountLiabilityAutoLoan] + personal_loan: Optional[AccountLiabilityPersonalLoan] + business_loan: Optional[AccountLiabilityBusinessLoan] + collection: Optional[AccountLiabilityCollection] + insurance: Optional[AccountLiabilityInsurance] + credit_builder: Optional[AccountLiabilityCreditBuilder] + subscription: Optional[AccountLiabilitySubscription] + utility: Optional[AccountLiabilityUtility] + medical: Optional[AccountLiabilityMedical] class AccountClearing(TypedDict): @@ -58,10 +272,26 @@ class AccountClearing(TypedDict): number: int -class AccountLiabilityCreateOpts(TypedDict): +class AccountCreateOpts(TypedDict): + holder_id: str + metadata: Optional[Dict[str, Any]] + + +class ACHCreateOpts(AccountCreateOpts): + ach: AccountACH + + +class LiabilityCreateOpts(TypedDict): mch_id: str account_number: str +class AccountLiabilityCreateOpts(AccountCreateOpts): + liability: Dict[LiabilityCreateOpts] + + +class ClearingCreateOpts(AccountCreateOpts): + clearing: Dict[type, AccountClearingSubTypesLiterals] + class Account(TypedDict): id: str @@ -72,79 +302,24 @@ class Account(TypedDict): liability: Optional[AccountLiability] clearing: Optional[AccountClearing] capabilities: List[AccountCapabilitiesLiterals] + available_capabilities: List[AccountCapabilitiesLiterals] error: Optional[ResourceError] created_at: str updated_at: str metadata: Optional[Dict[str, Any]] -class AccountCreateOpts(TypedDict): - holder_id: str - ach: Optional[AccountACH] - liability: Optional[AccountLiabilityCreateOpts] - metadata: Optional[Dict[str, Any]] - - -class AccountDetailBNPLLoanUpcomingPaymentDue(TypedDict): - amount: int - date: str - - -class AccountDetailBNPLLoan(TypedDict): - name: Optional[str] - reference_id: str - balance: int - purchase_date: str - next_payment_due_date: Optional[str] - total_payments_count: int - payments_made_count: int - remaining_payments_count: int - autopay_enabled: bool - payoff_progress: int - interest_rate: int - description: Optional[str] - total_cost: int - total_paid: int - status: Literal['paid_off', 'refunded', 'in_progress'] - upcoming_payments_due: List[AccountDetailBNPLLoanUpcomingPaymentDue] - - -class AccountDetailDepository(TypedDict): - name: Optional[str] - reference_number: str - balance: int - - -class AccountDetailCreditCard(TypedDict): - name: Optional[str] - reference_number: str - balance: int - last_payment_amount: int - last_payment_date: Optional[str] - next_payment_due_date: Optional[str] - next_payment_minimum_amount: int - - -# TODO[mdelcarmen] -class AccountDetailStudentLoan(TypedDict): - pass - - class AccountDetail(TypedDict): - type: AccountDetailTypesLiterals - bnpl_loan: Optional[AccountDetailBNPLLoan] - depository: Optional[AccountDetailDepository] - credit_card: Optional[AccountDetailCreditCard] - student_loan: Optional[AccountDetailStudentLoan] - - -class AccountTransaction(TypedDict): id: str - reference_id: str - date: str - amount: int - status: Literal['pending', 'success'] - description: Optional[str] + type: AccountTypesLiterals + aggregator: Optional[str] + name: str + institution_name: str + institution_logo: str + mask: str + created_at: str + updated_at: str + metadata: Optional[Dict[str, Any]] class AccountListOpts(TypedDict): @@ -156,10 +331,76 @@ class AccountListOpts(TypedDict): status: Optional[str] type: Optional[str] holder_id: Optional[str] + 'liability.mch_id': Optional[str] + 'liability.type': Optional[str] + + +class AccountCreateBulkSyncOpts(TypedDict): + acc_ids: List[str] + + +class AccountCreateBulkSyncResponse(TypedDict): + success: List[str] + failed: List[str] + results: [AccountSync] + + +class AccountSensitive(TypedDict): + number: Optional[str] + encrypted_number: Optional[str] + bin_4: Optional[str] + bin_6: Optional[str] + payment_address: Optional[Any] + + +class AccountCreateBulkSensitiveResponse(TypedDict): + success: List[str] + failed: List[str] + results: [AccountSensitive] + + +class AccountCreateBulkSensitiveOpts(TypedDict): + acc_ids: List[str] + + +class AccountWithdrawConsentOpts(TypedDict): + type: Literal['withdraw'] + reason: Optional[Literal['holder_withdrew_consent']] + + +class LiabilityMortgageUpdateOpts(TypedDict): + address_street: str + address_city: str + address_state: str + address_zip: str + + +class LiabilityCreditCardUpdateNumberOpts(TypedDict): + number: str + + +class LiabilityCreditCardUpdateExpirationOpts(TypedDict): + expiration_month: int + expiration_year: int + + +class LiabilityUpdateOpts(TypedDict): + mortgage: Optional[LiabilityMortgageUpdateOpts] + credit_card: Union[LiabilityCreditCardUpdateNumberOpts, LiabilityCreditCardUpdateExpirationOpts] + + +class CreditReportTradelinePaymentHistoryItem(TypedDict): + code: int + date: str + + +class AccountPaymentHistory(TypedDict): + payment_history: List[CreditReportTradelinePaymentHistoryItem] class AccountSubResources: verification: VerificationResource + sync: AccountSyncResource def __init__(self, _id: str, config: Configuration): self.verification = VerificationResource(config.add_path(_id)) @@ -175,23 +416,47 @@ def __call__(self, _id: str) -> AccountSubResources: def get(self, _id: str) -> Account: return super(AccountResource, self)._get_with_id(_id) + def update(self, _id: str, opts: LiabilityUpdateOpts) -> Account: + return super(AccountResource, self)._update_with_id(_id, opts) + def list(self, params: Optional[AccountListOpts] = None) -> List[Account]: return super(AccountResource, self)._list(params) - def create(self, opts: AccountCreateOpts, request_opts: Optional[RequestOpts] = None) -> Account: + def create(self, opts: Union[ACHCreateOpts, LiabilityCreateOpts, ClearingCreateOpts], request_opts: Optional[RequestOpts] = None) -> Account: return super(AccountResource, self)._create(opts, request_opts) + def get_payment_history(self, _id: str) -> AccountPaymentHistory: + return super(AccountResource, self)._get_with_sub_path('{_id}/payment_history'.format(_id=_id)) + def get_details(self, _id: str) -> AccountDetail: return super(AccountResource, self)._get_with_sub_path('{_id}/details'.format(_id=_id)) + def bulk_sync(self, acc_ids: AccountCreateBulkSyncOpts) -> AccountCreateBulkSyncResponse: + return super(AccountResource, self)._create_with_subpath( + '/bulk_sync', + { acc_ids } + ) + + def sync(self, _id: str) -> AccountSync: + return super(AccountResource, self)._create_with_sub_path('/{_id}/syncs'.format(_id=_id), {}) + + def bulkSensitive(self, acc_ids: AccountCreateBulkSensitiveOpts) -> AccountCreateBulkSensitiveResponse: + return super(AccountResource, self)._create_with_sub_path( + '/bulk_sensitive', + { acc_ids } + ) + + def sensitive(self, _id: str) -> AccountSensitive: + return super(AccountResource, self)._get_with_sub_path('/{_id}/sensitive'.format(_id=_id)) + def enroll_auto_syncs(self, _id: str) -> Account: return super(AccountResource, self)._create_with_sub_path('{_id}/sync_enrollment'.format(_id=_id), {}) def unenroll_auto_syncs(self, _id: str) -> Account: return super(AccountResource, self)._delete_with_sub_path('{_id}/sync_enrollment'.format(_id=_id)) - def withdraw_consent(self, _id: str) -> Account: + def withdraw_consent(self, _id: str, data: AccountWithdrawConsentOpts = { 'type': 'withdraw', 'reason': 'holder_withdrew_consent' }) -> Account: return super(AccountResource, self)._create_with_sub_path( '{_id}/consent'.format(_id=_id), - { 'type': 'withdraw', 'reason': 'holder_withdrew_consent' } + data ) From a1a5c4a30e81303f76ba9f07981556d434f349a3 Mon Sep 17 00:00:00 2001 From: stephenluc Date: Fri, 8 Sep 2023 21:10:45 -0500 Subject: [PATCH 09/32] update elements --- method/resources/Account.py | 8 +++--- method/resources/Element.py | 57 ++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/method/resources/Account.py b/method/resources/Account.py index 393ed33..48ec532 100644 --- a/method/resources/Account.py +++ b/method/resources/Account.py @@ -433,21 +433,21 @@ def get_details(self, _id: str) -> AccountDetail: def bulk_sync(self, acc_ids: AccountCreateBulkSyncOpts) -> AccountCreateBulkSyncResponse: return super(AccountResource, self)._create_with_subpath( - '/bulk_sync', + 'bulk_sync', { acc_ids } ) def sync(self, _id: str) -> AccountSync: - return super(AccountResource, self)._create_with_sub_path('/{_id}/syncs'.format(_id=_id), {}) + return super(AccountResource, self)._create_with_sub_path('{_id}/syncs'.format(_id=_id), {}) def bulkSensitive(self, acc_ids: AccountCreateBulkSensitiveOpts) -> AccountCreateBulkSensitiveResponse: return super(AccountResource, self)._create_with_sub_path( - '/bulk_sensitive', + 'bulk_sensitive', { acc_ids } ) def sensitive(self, _id: str) -> AccountSensitive: - return super(AccountResource, self)._get_with_sub_path('/{_id}/sensitive'.format(_id=_id)) + return super(AccountResource, self)._get_with_sub_path('{_id}/sensitive'.format(_id=_id)) def enroll_auto_syncs(self, _id: str) -> Account: return super(AccountResource, self)._create_with_sub_path('{_id}/sync_enrollment'.format(_id=_id), {}) diff --git a/method/resources/Element.py b/method/resources/Element.py index cc03472..84995af 100644 --- a/method/resources/Element.py +++ b/method/resources/Element.py @@ -1,4 +1,4 @@ -from typing import TypedDict, Optional, Literal, List +from typing import TypedDict, Optional, Literal, List, Dict from method.resource import Resource from method.configuration import Configuration @@ -8,6 +8,45 @@ ElementTypesLiterals = Literal['link'] +UserEventTypeLiterals = Literal[ + 'auth_intro_open', + 'auth_intro_continue', + 'auth_intro_close', + 'auth_name_open', + 'auth_name_continue', + 'auth_name_close', + 'auth_phone_open', + 'auth_phone_continue', + 'auth_phone_close', + 'auth_phone_verify_open', + 'auth_phone_verify_submit', + 'auth_phone_verify_close', + 'auth_dob_open', + 'auth_dob_continue', + 'auth_dob_close', + 'auth_address_open', + 'auth_address_continue', + 'auth_address_close', + 'auth_incorrect_info_open', + 'auth_incorrect_info_try_again', + 'auth_invalid_info_open', + 'auth_invalid_info_exit', + 'auth_secq_open', + 'auth_secq_continue', + 'auth_secq_close', + 'auth_secq_incorrect_open', + 'auth_secq_incorrect_try_again', + 'auth_secq_incorrect_close', + 'auth_consent_open', + 'auth_consent_continue', + 'auth_consent_close', + 'auth_success_open', + 'auth_success_continue', + 'auth_failure_open', + 'auth_failure_continue' +] + + class LinkElementLinkCreateOpts(TypedDict): mch_id: Optional[str] mask: Optional[str] @@ -24,6 +63,19 @@ class Element(TypedDict): element_token: str +class ElementUserEvent(TypedDict): + type: UserEventTypeLiterals + timestamp: str + metadata: Optional[Dict[str, any]] + +class TokenSessionResult(TypedDict): + authenticated: bool + cxn_id: Optional[str] + accounts: List[str] + entity_id: Optional[str] + events: List[ElementUserEvent] + + class ElementExchangePublicAccountOpts(TypedDict): public_account_token: Optional[str] public_account_tokens: Optional[List[str]] @@ -35,6 +87,9 @@ def __init__(self, config: Configuration): def create_token(self, opts: ElementTokenCreateOpts) -> Element: return super(ElementResource, self)._create_with_sub_path('token', opts) + + def get_session_results(self, _id: str) -> TokenSessionResult: + return super(ElementResource, self)._get_with_sub_path('token/{_id}/results'.format(_id=_id)) def exchange_public_account_token(self, opts: ElementExchangePublicAccountOpts) -> Account: return super(ElementResource, self)._create_with_sub_path('accounts/exchange', opts) From 26a13a708414aa86289bde70112e6d2dedc2fd8a Mon Sep 17 00:00:00 2001 From: stephenluc Date: Fri, 8 Sep 2023 21:17:20 -0500 Subject: [PATCH 10/32] update merchants --- method/resources/Entity.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/method/resources/Entity.py b/method/resources/Entity.py index fabe4ec..1e14df8 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -236,6 +236,7 @@ def list(self, params: EntityListOpts = None) -> List[Entity]: def create_auth_session(self, _id: str) -> EntityQuestionResponse: return super(EntityResource, self)._create_with_sub_path('{_id}/auth_session'.format(_id=_id), {}) +<<<<<<< HEAD def get_credit_score(self, _id: str) -> EntityQuestionResponse: return super(EntityResource, self)._get_with_sub_path('{_id}/credit_score'.format(_id=_id)) @@ -245,6 +246,8 @@ def get_credit_scores(self, _id: str, crs_id: str) -> EntityCreditScoresResponse def create_credit_scores(self, _id: str) -> EntityCreditScoresResponse: return super(EntityResource, self)._create_with_sub_path('{_id}/credit_scores'.format(_id=_id), {}) +======= +>>>>>>> 6276590 (update merchants) def update_auth_session(self, _id: str, opts: EntityUpdateAuthOpts) -> EntityUpdateAuthResponse: return super(EntityResource, self)._update_with_sub_path('{_id}/auth_session'.format(_id=_id), opts) From 3dcd962e74b66a1c711201c240c4e96c233e1e3e Mon Sep 17 00:00:00 2001 From: stephenluc Date: Fri, 8 Sep 2023 21:22:01 -0500 Subject: [PATCH 11/32] Update payments --- method/resources/Payment.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/method/resources/Payment.py b/method/resources/Payment.py index 6081d80..a6cf9ef 100644 --- a/method/resources/Payment.py +++ b/method/resources/Payment.py @@ -14,18 +14,8 @@ 'sent', 'reversed', 'reversal_required', - 'reversal_processing' -] - - -PaymentFundStatusesLiterals = Literal[ - 'hold', - 'pending', - 'requested', - 'clearing', - 'failed', - 'sent', - 'unknown' + 'reversal_processing', + 'settled' ] @@ -56,12 +46,13 @@ class Payment(TypedDict): amount: int description: str status: PaymentStatusesLiterals - fund_status: PaymentFundStatusesLiterals error: Optional[ResourceError] metadata: Optional[Dict[str, Any]] estimated_completion_date: Optional[str] source_settlement_date: Optional[str] destination_settlement_date: Optional[str] + source_status: PaymentStatusesLiterals + destination_status: PaymentStatusesLiterals fee: Optional[PaymentFee] type: PaymentTypesLiterals created_at: str @@ -88,6 +79,10 @@ class PaymentListOpts(TypedDict): source: Optional[str] destination: Optional[str] reversal_id: Optional[str] + source_holder_id: Optional[str] + destination_holder_id: Optional[str] + acc_id: Optional[str] + holder_id: Optional[str] class PaymentSubResources: From 12de7c7d07b220d0c2a26b87a1dade95dfecc788 Mon Sep 17 00:00:00 2001 From: stephenluc Date: Fri, 8 Sep 2023 21:23:27 -0500 Subject: [PATCH 12/32] Update reports --- method/resources/Report.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/method/resources/Report.py b/method/resources/Report.py index 46a4838..016e5fc 100644 --- a/method/resources/Report.py +++ b/method/resources/Report.py @@ -8,14 +8,15 @@ 'payments.created.current', 'payments.created.previous', 'payments.updated.current', - 'payments.updated.previous' + 'payments.updated.previous', + 'ach.pull.upcoming', + 'ach.pull.previous', + 'ach.pull.nightly', + 'ach.reversals.nightly' ] -ReportStatusesLiterals = Literal[ - 'processing', - 'completed' -] +ReportStatusesLiterals = Literal['completed'] class Report(TypedDict): From 1c8dd2fb01f84798366b1458fb22b3e646c5db01 Mon Sep 17 00:00:00 2001 From: stephenluc Date: Fri, 8 Sep 2023 21:38:24 -0500 Subject: [PATCH 13/32] Update webhooks --- method/resources/Account.py | 15 ++++++++++----- method/resources/Webhook.py | 6 ++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/method/resources/Account.py b/method/resources/Account.py index 48ec532..16e76a4 100644 --- a/method/resources/Account.py +++ b/method/resources/Account.py @@ -277,7 +277,7 @@ class AccountCreateOpts(TypedDict): metadata: Optional[Dict[str, Any]] -class ACHCreateOpts(AccountCreateOpts): +class AccountACHCreateOpts(AccountCreateOpts): ach: AccountACH @@ -285,12 +285,17 @@ class LiabilityCreateOpts(TypedDict): mch_id: str account_number: str + class AccountLiabilityCreateOpts(AccountCreateOpts): - liability: Dict[LiabilityCreateOpts] + liability: LiabilityCreateOpts + + +class ClearingCreateOpts(TypedDict): + type: AccountClearingSubTypesLiterals -class ClearingCreateOpts(AccountCreateOpts): - clearing: Dict[type, AccountClearingSubTypesLiterals] +class AccountClearingCreateOpts(AccountCreateOpts): + clearing: ClearingCreateOpts class Account(TypedDict): @@ -422,7 +427,7 @@ def update(self, _id: str, opts: LiabilityUpdateOpts) -> Account: def list(self, params: Optional[AccountListOpts] = None) -> List[Account]: return super(AccountResource, self)._list(params) - def create(self, opts: Union[ACHCreateOpts, LiabilityCreateOpts, ClearingCreateOpts], request_opts: Optional[RequestOpts] = None) -> Account: + def create(self, opts: Union[AccountACHCreateOpts, AccountLiabilityCreateOpts, AccountClearingCreateOpts], request_opts: Optional[RequestOpts] = None) -> Account: return super(AccountResource, self)._create(opts, request_opts) def get_payment_history(self, _id: str) -> AccountPaymentHistory: diff --git a/method/resources/Webhook.py b/method/resources/Webhook.py index fdac5e2..ad871dd 100644 --- a/method/resources/Webhook.py +++ b/method/resources/Webhook.py @@ -17,6 +17,12 @@ 'connection.update', 'account_verification.create', 'account_verification.update', + 'transaction.create', + 'transaction.update', + 'report.create', + 'report.update', + + # Deprecated 'account_verification.sent', 'account_verification.returned' ] From 3a333e779a9ba09d1958040570ce558d99b2295d Mon Sep 17 00:00:00 2001 From: stephenluc Date: Mon, 11 Sep 2023 13:43:54 -0400 Subject: [PATCH 14/32] Addd funds back --- method/resources/Payment.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/method/resources/Payment.py b/method/resources/Payment.py index a6cf9ef..f5fa44f 100644 --- a/method/resources/Payment.py +++ b/method/resources/Payment.py @@ -19,6 +19,21 @@ ] +PaymentFundStatusesLiterals = Literal[ + 'transmitting', + 'transmitted', + 'hold', + 'pending', + 'requested', + 'clearing', + 'failed', + 'sent', + 'unknown', + 'pending_consolidation', + 'pending_clearing' +] + + PaymentTypesLiterals = Literal[ 'standard', 'clearing' @@ -46,6 +61,7 @@ class Payment(TypedDict): amount: int description: str status: PaymentStatusesLiterals + fund_status: Optional[PaymentFundStatusesLiterals] error: Optional[ResourceError] metadata: Optional[Dict[str, Any]] estimated_completion_date: Optional[str] From 2406c36ac3b8d4cf8a75720260161410db38e3bb Mon Sep 17 00:00:00 2001 From: stephenluc Date: Tue, 12 Sep 2023 18:32:04 -0400 Subject: [PATCH 15/32] update entities --- method/resources/Entity.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/method/resources/Entity.py b/method/resources/Entity.py index 1e14df8..fabe4ec 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -236,7 +236,6 @@ def list(self, params: EntityListOpts = None) -> List[Entity]: def create_auth_session(self, _id: str) -> EntityQuestionResponse: return super(EntityResource, self)._create_with_sub_path('{_id}/auth_session'.format(_id=_id), {}) -<<<<<<< HEAD def get_credit_score(self, _id: str) -> EntityQuestionResponse: return super(EntityResource, self)._get_with_sub_path('{_id}/credit_score'.format(_id=_id)) @@ -246,8 +245,6 @@ def get_credit_scores(self, _id: str, crs_id: str) -> EntityCreditScoresResponse def create_credit_scores(self, _id: str) -> EntityCreditScoresResponse: return super(EntityResource, self)._create_with_sub_path('{_id}/credit_scores'.format(_id=_id), {}) -======= ->>>>>>> 6276590 (update merchants) def update_auth_session(self, _id: str, opts: EntityUpdateAuthOpts) -> EntityUpdateAuthResponse: return super(EntityResource, self)._update_with_sub_path('{_id}/auth_session'.format(_id=_id), opts) From c1ceecbb3d2e1d2c86ad45c1dac32aa82f75ba70 Mon Sep 17 00:00:00 2001 From: stephenluc Date: Tue, 12 Sep 2023 18:42:49 -0400 Subject: [PATCH 16/32] Add new entity endpoints --- method/resources/Entity.py | 41 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/method/resources/Entity.py b/method/resources/Entity.py index fabe4ec..ce08c98 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -217,6 +217,38 @@ class EntityUpdateAuthResponse(TypedDict): cxn_id: Optional[str] +class EntityKYCAddressRecordData(TypedDict): + address: str + city: str + postal_code: str + state: str + address_term: int + + +class EntityIdentity(TypedDict): + first_name: Optional[str] + last_name: Optional[str] + phone: Optional[str] + dob: Optional[str] + address: Optional[EntityKYCAddressRecordData] + ssn: Optional[str] + + +class EntitySensitiveResponse(TypedDict): + first_name: Optional[str] + last_name: Optional[str] + phone: Optional[str] + phone_history: Optional[List[str]] + email: Optional[str] + dob: Optional[str] + address: Optional[EntityKYCAddressRecordData] + address_history: List[EntityKYCAddressRecordData] + ssn_4: Optional[str] + ssn_6: Optional[str] + ssn_9: Optional[str] + identities: List[EntityIdentity] + + class EntityResource(Resource): def __init__(self, config: Configuration): super(EntityResource, self).__init__(config.add_path('entities')) @@ -248,7 +280,11 @@ def create_credit_scores(self, _id: str) -> EntityCreditScoresResponse: def update_auth_session(self, _id: str, opts: EntityUpdateAuthOpts) -> EntityUpdateAuthResponse: return super(EntityResource, self)._update_with_sub_path('{_id}/auth_session'.format(_id=_id), opts) - # TODO: Add create and update manual auth session + def create_manual_auth_session(self, _id: str, opts: EntityManualAuthOpts) -> EntityManualAuthResponse: + return super(EntityResource, self)._create_with_sub_path('{_id}/manual_auth_session'.format(_id=_id), opts) + + def update_manual_auth_session(self, _id: str, opts: EntityManualAuthOpts) -> EntityManualAuthResponse: + return super(EntityResource, self)._update_with_sub_path('{_id}/manual_auth_session'.format(_id=_id), opts) def refresh_capabilities(self, _id: str) -> Entity: return super(EntityResource, self)._create_with_sub_path('{_id}/refresh_capabilities'.format(_id=_id), {}) @@ -256,7 +292,8 @@ def refresh_capabilities(self, _id: str) -> Entity: def get_credit_score(self, _id: str) -> EntityQuestionResponse: return super(EntityResource, self)._get_with_sub_path('{_id}/credit_score'.format(_id=_id)) - # TODO: get sensitive fields + def get_sensitive_fields(self, _id: str) -> EntitySensitiveResponse: + return super(EntityResource, self)._get_with_sub_path('{_id}/sensitive'.format(_id=_id)) def withdraw_consent(self, _id: str) -> Entity: return super(EntityResource, self)._create_with_sub_path( From 60f5b6da26d4895905a058bc78910ae9bbf4ba6f Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Wed, 20 Dec 2023 12:09:51 -0500 Subject: [PATCH 17/32] added student loans, trended, delinquent items --- method/resources/Account.py | 66 +++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/method/resources/Account.py b/method/resources/Account.py index 16e76a4..221a9da 100644 --- a/method/resources/Account.py +++ b/method/resources/Account.py @@ -52,6 +52,7 @@ AccountLiabilityTypesLiterals = Literal[ 'student_loan', + 'student_loans', 'credit_card', 'mortgage', 'auto_loan', @@ -109,6 +110,24 @@ ] +DelinquencyStatusLiterals = Literal[ + 'good_standing', + 'past_due', + 'major_delinquency' + 'unavailable' +] + + +DelinquencyPeriodLiterals = Literal[ + 'less_than_30', + '30', + '60', + '90', + '120', + 'over_120' +] + + # Typed Classes class AccountACH(TypedDict): routing: int @@ -172,6 +191,52 @@ class AccountLiabilityStudentLoan(AccountLiabilityLoan): payoff_amount: Optional[int] payoff_amount_term: Optional[int] principal_balance: Optional[int] + + +class DelinquencyHistoryItem(TypedDict): + start_date: str + end_date: str + status: DelinquencyStatusLiterals + period: Optional[DelinquencyPeriodLiterals] + + +class TrendedDataItem(TypedDict): + month: Optional[int] + year: Optional[int] + balance: Optional[int] + available_credit: Optional[int] + scheduled_payment: Optional[int] + actual_payment: Optional[int] + high_credit: Optional[int] + credit_limit: Optional[int] + amount_past_due: Optional[int] + last_payment_date: Optional[str] + account_status: str + payment_status:str + + +class AccountLiabilityStudentLoansDisbursement(AccountLiabilityLoan): + sequence: int + disbursed_at: Optional[str] + expected_payoff_date: Optional[str] + delinquent_status: Optional[str] + delinquent_amount: Optional[int] + delinquent_period: Optional[int] + delinquent_action: Optional[str] + delinquent_start_date: Optional[str] + delinquent_major_start_date: Optional[str] + delinquent_status_updated_at: Optional[str] + delinquent_history: Optional[List[DelinquencyHistoryItem]] + delinquent_action: Optional[List[TrendedDataItem]] + + +class AccountLiabilityStudentLoans(AccountLiabilityLoan): + sub_type: Optional[Literal['federal', 'private']] + disbursed_at: Optional[str] + expected_payoff_date: Optional[str] + interest_rate_type: Optional[Literal['fixed', 'variable']] + expected_payoff_date: Optional[str] + disbursements: Optional[AccountLiabilityStudentLoansDisbursement] class AccountLiabilityMortgage(AccountLiabilityLoan): @@ -254,6 +319,7 @@ class AccountLiability(TypedDict): type: AccountLiabilityTypesLiterals loan: Optional[AccountLiabilityLoan] student_loan: Optional[AccountLiabilityStudentLoan] + student_loans: Optional[AccountLiabilityStudentLoans] credit_card: Optional[AccountLiabilityCreditCard] mortgage: Optional[AccountLiabilityMortgage] auto_loan: Optional[AccountLiabilityAutoLoan] From 31775c319b33201ceb561f42132478099563f4af Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Wed, 20 Dec 2023 12:11:42 -0500 Subject: [PATCH 18/32] removed connections from README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc68c12..9901e04 100644 --- a/README.md +++ b/README.md @@ -417,4 +417,4 @@ report = method.reports.get('rpt_cj2mkA3hFyHT5') ```python report_csv = method.reports.download('rpt_cj2mkA3hFyHT5') -``` \ No newline at end of file +``` From 356146df31eca7d50697eedcffc40c07bb56bc94 Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Wed, 20 Dec 2023 12:49:34 -0500 Subject: [PATCH 19/32] updated version to 0.0.33 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fc24aaa..af65c31 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='method-python', - version='0.0.32', + version='0.0.33', description='Python library for the Method API', long_description='Python library for the Method API', long_description_content_type='text/x-rst', From 30cc4946fee2369765c143e39f5467215d3f01b3 Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Thu, 4 Jan 2024 12:09:50 -0500 Subject: [PATCH 20/32] resolved spacing, snake_case, and Payment typings --- method/resources/Account.py | 244 ++++++++++++++++++------------------ method/resources/Payment.py | 18 ++- 2 files changed, 129 insertions(+), 133 deletions(-) diff --git a/method/resources/Account.py b/method/resources/Account.py index 221a9da..d45d5fc 100644 --- a/method/resources/Account.py +++ b/method/resources/Account.py @@ -111,20 +111,20 @@ DelinquencyStatusLiterals = Literal[ - 'good_standing', - 'past_due', - 'major_delinquency' - 'unavailable' + 'good_standing', + 'past_due', + 'major_delinquency' + 'unavailable' ] DelinquencyPeriodLiterals = Literal[ - 'less_than_30', - '30', - '60', - '90', - '120', - 'over_120' + 'less_than_30', + '30', + '60', + '90', + '120', + 'over_120' ] @@ -136,83 +136,83 @@ class AccountACH(TypedDict): class AccountLiabilityLoan(TypedDict): - name: str - balance: Optional[int] - opened_at: Optional[str] - original_loan_amount: Optional[int] - sub_type: Optional[str] - term_length: Optional[int] - closed_at: Optional[str] - last_payment_amount: Optional[int] - last_payment_date: Optional[str] - next_payment_minimum_amount: Optional[int] - next_payment_due_date: Optional[str] - interest_rate_type: Literal['fixed', 'variable'] - interest_rate_percentage: Optional[int] - interest_rate_source: Optional[Literal['financial_institution', 'public_data', 'method']] + name: str + balance: Optional[int] + opened_at: Optional[str] + original_loan_amount: Optional[int] + sub_type: Optional[str] + term_length: Optional[int] + closed_at: Optional[str] + last_payment_amount: Optional[int] + last_payment_date: Optional[str] + next_payment_minimum_amount: Optional[int] + next_payment_due_date: Optional[str] + interest_rate_type: Literal['fixed', 'variable'] + interest_rate_percentage: Optional[int] + interest_rate_source: Optional[Literal['financial_institution', 'public_data', 'method']] class AccountLiabilityCreditCard(AccountLiabilityLoan): - last_statement_balance: Optional[int] - remaining_statement_balance: Optional[int] - available_credit: Optional[int] - auto_pay_status: Optional[AutoPayStatusesLiterals] - auto_pay_amount: Optional[int] - auto_pay_date: Optional[str] - past_due_status: Optional[PastDueStatusesLiterals] - past_due_balance: Optional[int] - past_due_date: Optional[str] - credit_limit: Optional[int] - pending_purchase_authorization_amount: Optional[int] - pending_credit_authorization_amount: Optional[int] - interest_saving_balance: Optional[int] - next_statement_date: Optional[str] + last_statement_balance: Optional[int] + remaining_statement_balance: Optional[int] + available_credit: Optional[int] + auto_pay_status: Optional[AutoPayStatusesLiterals] + auto_pay_amount: Optional[int] + auto_pay_date: Optional[str] + past_due_status: Optional[PastDueStatusesLiterals] + past_due_balance: Optional[int] + past_due_date: Optional[str] + credit_limit: Optional[int] + pending_purchase_authorization_amount: Optional[int] + pending_credit_authorization_amount: Optional[int] + interest_saving_balance: Optional[int] + next_statement_date: Optional[str] class AccountLiabilityAutoLoan(AccountLiabilityLoan): - sub_type: Optional[Literal['lease', 'loan']] - payoff_amount: Optional[int] - payoff_amount_term: Optional[int] - past_due_status: Optional[PastDueStatusesLiterals] - past_due_balance: Optional[int] - past_due_date: Optional[str] - late_fees_amount: Optional[int] - expected_payoff_date: Optional[str] - principal_balance: Optional[int] - per_diem_amount: Optional[int] - mileage_allocation: Optional[int] + sub_type: Optional[Literal['lease', 'loan']] + payoff_amount: Optional[int] + payoff_amount_term: Optional[int] + past_due_status: Optional[PastDueStatusesLiterals] + past_due_balance: Optional[int] + past_due_date: Optional[str] + late_fees_amount: Optional[int] + expected_payoff_date: Optional[str] + principal_balance: Optional[int] + per_diem_amount: Optional[int] + mileage_allocation: Optional[int] class AccountLiabilityStudentLoan(AccountLiabilityLoan): - sub_type: Optional[Literal['federal', 'private']] - sequence: Optional[int] - disbursed_at: Optional[str] - expected_payoff_date: Optional[str] - payoff_amount: Optional[int] - payoff_amount_term: Optional[int] - principal_balance: Optional[int] + sub_type: Optional[Literal['federal', 'private']] + sequence: Optional[int] + disbursed_at: Optional[str] + expected_payoff_date: Optional[str] + payoff_amount: Optional[int] + payoff_amount_term: Optional[int] + principal_balance: Optional[int] class DelinquencyHistoryItem(TypedDict): - start_date: str - end_date: str - status: DelinquencyStatusLiterals - period: Optional[DelinquencyPeriodLiterals] + start_date: str + end_date: str + status: DelinquencyStatusLiterals + period: Optional[DelinquencyPeriodLiterals] class TrendedDataItem(TypedDict): - month: Optional[int] - year: Optional[int] - balance: Optional[int] - available_credit: Optional[int] - scheduled_payment: Optional[int] - actual_payment: Optional[int] - high_credit: Optional[int] - credit_limit: Optional[int] - amount_past_due: Optional[int] - last_payment_date: Optional[str] - account_status: str - payment_status:str + month: Optional[int] + year: Optional[int] + balance: Optional[int] + available_credit: Optional[int] + scheduled_payment: Optional[int] + actual_payment: Optional[int] + high_credit: Optional[int] + credit_limit: Optional[int] + amount_past_due: Optional[int] + last_payment_date: Optional[str] + account_status: str + payment_status:str class AccountLiabilityStudentLoansDisbursement(AccountLiabilityLoan): @@ -231,39 +231,39 @@ class AccountLiabilityStudentLoansDisbursement(AccountLiabilityLoan): class AccountLiabilityStudentLoans(AccountLiabilityLoan): - sub_type: Optional[Literal['federal', 'private']] - disbursed_at: Optional[str] - expected_payoff_date: Optional[str] - interest_rate_type: Optional[Literal['fixed', 'variable']] - expected_payoff_date: Optional[str] - disbursements: Optional[AccountLiabilityStudentLoansDisbursement] + sub_type: Optional[Literal['federal', 'private']] + disbursed_at: Optional[str] + expected_payoff_date: Optional[str] + interest_rate_type: Optional[Literal['fixed', 'variable']] + expected_payoff_date: Optional[str] + disbursements: Optional[AccountLiabilityStudentLoansDisbursement] class AccountLiabilityMortgage(AccountLiabilityLoan): - principal_balance: Optional[int] - expected_payoff_date: Optional[str] - address_street: Optional[str] - address_city: Optional[str] - address_state: Optional[str] - address_zip: Optional[str] - property_value: Optional[int] - past_due_status: Optional[PastDueStatusesLiterals] - past_due_balance: Optional[int] - past_due_date: Optional[str] - payoff_amount: Optional[int] - payoff_amount_term: Optional[int] - year_to_date_interest_paid: Optional[int] - year_to_date_principal_paid: Optional[int] - year_to_date_taxes_paid: Optional[int] - year_start_principal_balance: Optional[int] - escrow_balance: Optional[int] + principal_balance: Optional[int] + expected_payoff_date: Optional[str] + address_street: Optional[str] + address_city: Optional[str] + address_state: Optional[str] + address_zip: Optional[str] + property_value: Optional[int] + past_due_status: Optional[PastDueStatusesLiterals] + past_due_balance: Optional[int] + past_due_date: Optional[str] + payoff_amount: Optional[int] + payoff_amount_term: Optional[int] + year_to_date_interest_paid: Optional[int] + year_to_date_principal_paid: Optional[int] + year_to_date_taxes_paid: Optional[int] + year_start_principal_balance: Optional[int] + escrow_balance: Optional[int] class AccountLiabilityPersonalLoan(AccountLiabilityLoan): - expected_payoff_date: Optional[str] - available_credit: Optional[int] - principal_balance: Optional[int] - year_to_date_interest_paid: Optional[int] + expected_payoff_date: Optional[str] + available_credit: Optional[int] + principal_balance: Optional[int] + year_to_date_interest_paid: Optional[int] class AccountLiabilityCreditBuilder(AccountLiabilityLoan): @@ -271,37 +271,37 @@ class AccountLiabilityCreditBuilder(AccountLiabilityLoan): class AccountLiabilityCollection(AccountLiabilityLoan): - pass + pass class AccountLiabilityBusinessLoan(TypedDict): - name: str - balance: Optional[int] - opened_at: Optional[str] + name: str + balance: Optional[int] + opened_at: Optional[str] class AccountLiabilityInsurance(TypedDict): - name: str - balance: Optional[int] - opened_at: Optional[str] + name: str + balance: Optional[int] + opened_at: Optional[str] class AccountLiabilitySubscription(TypedDict): - name: str - balance: Optional[int] - opened_at: Optional[str] + name: str + balance: Optional[int] + opened_at: Optional[str] class AccountLiabilityUtility(TypedDict): - name: str - balance: Optional[int] - opened_at: Optional[str] + name: str + balance: Optional[int] + opened_at: Optional[str] class AccountLiabilityMedical(TypedDict): - name: str - balance: Optional[int] - opened_at: Optional[str] + name: str + balance: Optional[int] + opened_at: Optional[str] class AccountLiability(TypedDict): @@ -435,8 +435,8 @@ class AccountCreateBulkSensitiveOpts(TypedDict): class AccountWithdrawConsentOpts(TypedDict): - type: Literal['withdraw'] - reason: Optional[Literal['holder_withdrew_consent']] + type: Literal['withdraw'] + reason: Optional[Literal['holder_withdrew_consent']] class LiabilityMortgageUpdateOpts(TypedDict): @@ -447,12 +447,12 @@ class LiabilityMortgageUpdateOpts(TypedDict): class LiabilityCreditCardUpdateNumberOpts(TypedDict): - number: str + number: str class LiabilityCreditCardUpdateExpirationOpts(TypedDict): - expiration_month: int - expiration_year: int + expiration_month: int + expiration_year: int class LiabilityUpdateOpts(TypedDict): @@ -466,7 +466,7 @@ class CreditReportTradelinePaymentHistoryItem(TypedDict): class AccountPaymentHistory(TypedDict): - payment_history: List[CreditReportTradelinePaymentHistoryItem] + payment_history: List[CreditReportTradelinePaymentHistoryItem] class AccountSubResources: @@ -511,7 +511,7 @@ def bulk_sync(self, acc_ids: AccountCreateBulkSyncOpts) -> AccountCreateBulkSync def sync(self, _id: str) -> AccountSync: return super(AccountResource, self)._create_with_sub_path('{_id}/syncs'.format(_id=_id), {}) - def bulkSensitive(self, acc_ids: AccountCreateBulkSensitiveOpts) -> AccountCreateBulkSensitiveResponse: + def bulk_sensitive(self, acc_ids: AccountCreateBulkSensitiveOpts) -> AccountCreateBulkSensitiveResponse: return super(AccountResource, self)._create_with_sub_path( 'bulk_sensitive', { acc_ids } diff --git a/method/resources/Payment.py b/method/resources/Payment.py index f5fa44f..404735a 100644 --- a/method/resources/Payment.py +++ b/method/resources/Payment.py @@ -20,17 +20,13 @@ PaymentFundStatusesLiterals = Literal[ - 'transmitting', - 'transmitted', - 'hold', - 'pending', - 'requested', - 'clearing', - 'failed', - 'sent', - 'unknown', - 'pending_consolidation', - 'pending_clearing' + 'hold', + 'pending', + 'requested', + 'clearing', + 'failed', + 'sent', + 'unknown' ] From f086582f18b3b5a379881f528f60c203fd066f3d Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Wed, 13 Dec 2023 15:06:20 -0500 Subject: [PATCH 21/32] removed deprecated connections. Added credit_scores endpoint --- README.md | 2 +- method/resources/Connection.py | 53 ---------------------------------- method/resources/Entity.py | 16 ++++++++++ 3 files changed, 17 insertions(+), 54 deletions(-) delete mode 100644 method/resources/Connection.py diff --git a/README.md b/README.md index 9901e04..bc68c12 100644 --- a/README.md +++ b/README.md @@ -417,4 +417,4 @@ report = method.reports.get('rpt_cj2mkA3hFyHT5') ```python report_csv = method.reports.download('rpt_cj2mkA3hFyHT5') -``` +``` \ No newline at end of file diff --git a/method/resources/Connection.py b/method/resources/Connection.py deleted file mode 100644 index c38f67b..0000000 --- a/method/resources/Connection.py +++ /dev/null @@ -1,53 +0,0 @@ -from typing import TypedDict, Optional, List, Literal - -from method.resources import Account -from method.errors import ResourceError -from method.resource import Resource -from method.configuration import Configuration - - -ConnectionSourcesLiterals = Literal[ - 'plaid', - 'mch_5500' -] - - -ConnectionStatusesLiterals = Literal[ - 'success', - 'reauth_required', - 'syncing', - 'failed' -] - - -class Connection(TypedDict): - id: str - entity_id: str - accounts: List[str] - source: ConnectionSourcesLiterals - status: ConnectionStatusesLiterals - error: Optional[ResourceError] - created_at: str - updated_at: str - last_synced_at: str - - -class ConnectionUpdateOpts(TypedDict): - status: Literal['syncing'] - - -class ConnectionResource(Resource): - def __init__(self, config: Configuration): - super(ConnectionResource, self).__init__(config.add_path('connections')) - - def get(self, _id: str) -> Connection: - return super(ConnectionResource, self)._get_with_id(_id) - - def list(self) -> List[Connection]: - return super(ConnectionResource, self)._list(None) - - def update(self, _id: str, opts: ConnectionUpdateOpts) -> Connection: - return super(ConnectionResource, self)._update_with_id(_id, opts) - - def get_public_account_tokens(self, _id: str) -> List[str]: - return super(ConnectionResource, self)._get_with_sub_path('{_id}/public_account_tokens'.format(_id=_id)) diff --git a/method/resources/Entity.py b/method/resources/Entity.py index ce08c98..a684503 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -47,6 +47,14 @@ ] +CreditScoreStatusesLiterals = Literal[ + 'completed', + 'in_progress', + 'pending', + 'failed' +] + + CreditReportBureausLiterals = Literal[ 'experian', 'equifax', @@ -156,12 +164,16 @@ class EntityCreditScoresFactorsType(TypedDict): code: str description: str + class EntityCreditScoresType(TypedDict): score: int source: CreditReportBureausLiterals model: str factors: List[EntityCreditScoresFactorsType] created_at: str + factors: EntityCreditScoresFactorsType + created_at: str + class EntityCreditScoresResponse(TypedDict): id: str @@ -170,6 +182,10 @@ class EntityCreditScoresResponse(TypedDict): error: Optional[ResourceError] created_at: str updated_at: str +<<<<<<< HEAD +======= + +>>>>>>> d3c13a0 (removed deprecated connections. Added credit_scores endpoint) class AnswerOpts(TypedDict): question_id: str From 20349fc037f595babd9090eb4aaf7421c206faad Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Wed, 13 Dec 2023 15:08:50 -0500 Subject: [PATCH 22/32] fixed factors type in EntityCreditScoresType --- method/resources/Entity.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/method/resources/Entity.py b/method/resources/Entity.py index a684503..dfbf221 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -182,10 +182,7 @@ class EntityCreditScoresResponse(TypedDict): error: Optional[ResourceError] created_at: str updated_at: str -<<<<<<< HEAD -======= ->>>>>>> d3c13a0 (removed deprecated connections. Added credit_scores endpoint) class AnswerOpts(TypedDict): question_id: str From 2f3ad6cb2a6cb664b049a670aa96c0e7e90f5d60 Mon Sep 17 00:00:00 2001 From: stephenluc Date: Fri, 8 Sep 2023 21:17:20 -0500 Subject: [PATCH 23/32] update merchants --- method/resources/Entity.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/method/resources/Entity.py b/method/resources/Entity.py index dfbf221..af3418f 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -184,6 +184,28 @@ class EntityCreditScoresResponse(TypedDict): updated_at: str +class EntityCreditScoresFactorsType(TypedDict): + code: str + description: str + + +class EntityCreditScoresType(TypedDict): + score: int + source: CreditReportBureausLiterals + model: str + factors: List[EntityCreditScoresFactorsType] + created_at: str + + +class EntityCreditScoresResponse(TypedDict): + id: str + status: EntityStatusesLiterals + credit_scores: Optional[List[EntityCreditScoresType]] + error: Optional[ResourceError] + created_at: str + updated_at: str + + class AnswerOpts(TypedDict): question_id: str answer_id: str @@ -298,6 +320,7 @@ def create_manual_auth_session(self, _id: str, opts: EntityManualAuthOpts) -> En def update_manual_auth_session(self, _id: str, opts: EntityManualAuthOpts) -> EntityManualAuthResponse: return super(EntityResource, self)._update_with_sub_path('{_id}/manual_auth_session'.format(_id=_id), opts) + # TODO: Add create and update manual auth session def refresh_capabilities(self, _id: str) -> Entity: return super(EntityResource, self)._create_with_sub_path('{_id}/refresh_capabilities'.format(_id=_id), {}) @@ -307,6 +330,7 @@ def get_credit_score(self, _id: str) -> EntityQuestionResponse: def get_sensitive_fields(self, _id: str) -> EntitySensitiveResponse: return super(EntityResource, self)._get_with_sub_path('{_id}/sensitive'.format(_id=_id)) + # TODO: get sensitive fields def withdraw_consent(self, _id: str) -> Entity: return super(EntityResource, self)._create_with_sub_path( From d13e845cbe6a255088948d261c4ec28f7e78952c Mon Sep 17 00:00:00 2001 From: stephenluc Date: Fri, 8 Sep 2023 21:52:46 -0500 Subject: [PATCH 24/32] Add transactions --- method/resources/Connection.py | 53 ++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 method/resources/Connection.py diff --git a/method/resources/Connection.py b/method/resources/Connection.py new file mode 100644 index 0000000..c38f67b --- /dev/null +++ b/method/resources/Connection.py @@ -0,0 +1,53 @@ +from typing import TypedDict, Optional, List, Literal + +from method.resources import Account +from method.errors import ResourceError +from method.resource import Resource +from method.configuration import Configuration + + +ConnectionSourcesLiterals = Literal[ + 'plaid', + 'mch_5500' +] + + +ConnectionStatusesLiterals = Literal[ + 'success', + 'reauth_required', + 'syncing', + 'failed' +] + + +class Connection(TypedDict): + id: str + entity_id: str + accounts: List[str] + source: ConnectionSourcesLiterals + status: ConnectionStatusesLiterals + error: Optional[ResourceError] + created_at: str + updated_at: str + last_synced_at: str + + +class ConnectionUpdateOpts(TypedDict): + status: Literal['syncing'] + + +class ConnectionResource(Resource): + def __init__(self, config: Configuration): + super(ConnectionResource, self).__init__(config.add_path('connections')) + + def get(self, _id: str) -> Connection: + return super(ConnectionResource, self)._get_with_id(_id) + + def list(self) -> List[Connection]: + return super(ConnectionResource, self)._list(None) + + def update(self, _id: str, opts: ConnectionUpdateOpts) -> Connection: + return super(ConnectionResource, self)._update_with_id(_id, opts) + + def get_public_account_tokens(self, _id: str) -> List[str]: + return super(ConnectionResource, self)._get_with_sub_path('{_id}/public_account_tokens'.format(_id=_id)) From 6e7cca13b8ad4bef1f5b7e191b8e15d5d8b248ae Mon Sep 17 00:00:00 2001 From: stephenluc Date: Tue, 12 Sep 2023 18:32:04 -0400 Subject: [PATCH 25/32] update entities --- method/resources/Entity.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/method/resources/Entity.py b/method/resources/Entity.py index af3418f..f62e5e9 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -47,6 +47,7 @@ ] +<<<<<<< HEAD CreditScoreStatusesLiterals = Literal[ 'completed', 'in_progress', @@ -55,6 +56,8 @@ ] +======= +>>>>>>> 5753f79 (update entities) CreditReportBureausLiterals = Literal[ 'experian', 'equifax', @@ -250,6 +253,7 @@ class EntityUpdateAuthOpts(TypedDict): class EntityUpdateAuthResponse(TypedDict): questions: List[EntityQuestion] cxn_id: Optional[str] +<<<<<<< HEAD class EntityKYCAddressRecordData(TypedDict): @@ -282,6 +286,8 @@ class EntitySensitiveResponse(TypedDict): ssn_6: Optional[str] ssn_9: Optional[str] identities: List[EntityIdentity] +======= +>>>>>>> d934838 (update entities) class EntityResource(Resource): From 3a722ce7cb07c71d038867a6f31584e3904b12a8 Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Thu, 4 Jan 2024 14:34:48 -0500 Subject: [PATCH 26/32] rebase completed --- method/resources/Entity.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/method/resources/Entity.py b/method/resources/Entity.py index f62e5e9..a960351 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -253,7 +253,6 @@ class EntityUpdateAuthOpts(TypedDict): class EntityUpdateAuthResponse(TypedDict): questions: List[EntityQuestion] cxn_id: Optional[str] -<<<<<<< HEAD class EntityKYCAddressRecordData(TypedDict): @@ -286,8 +285,6 @@ class EntitySensitiveResponse(TypedDict): ssn_6: Optional[str] ssn_9: Optional[str] identities: List[EntityIdentity] -======= ->>>>>>> d934838 (update entities) class EntityResource(Resource): From a5a12e704a74e94c63bf57f9086884545d5f500d Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Thu, 4 Jan 2024 14:43:54 -0500 Subject: [PATCH 27/32] fixing Entity file --- method/resources/Entity.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/method/resources/Entity.py b/method/resources/Entity.py index a960351..af3418f 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -47,7 +47,6 @@ ] -<<<<<<< HEAD CreditScoreStatusesLiterals = Literal[ 'completed', 'in_progress', @@ -56,8 +55,6 @@ ] -======= ->>>>>>> 5753f79 (update entities) CreditReportBureausLiterals = Literal[ 'experian', 'equifax', From a77d994094d8e0cf041c2fc445633ea782d299da Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Thu, 4 Jan 2024 14:49:37 -0500 Subject: [PATCH 28/32] removed Connection --- method/resources/Connection.py | 53 ---------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 method/resources/Connection.py diff --git a/method/resources/Connection.py b/method/resources/Connection.py deleted file mode 100644 index c38f67b..0000000 --- a/method/resources/Connection.py +++ /dev/null @@ -1,53 +0,0 @@ -from typing import TypedDict, Optional, List, Literal - -from method.resources import Account -from method.errors import ResourceError -from method.resource import Resource -from method.configuration import Configuration - - -ConnectionSourcesLiterals = Literal[ - 'plaid', - 'mch_5500' -] - - -ConnectionStatusesLiterals = Literal[ - 'success', - 'reauth_required', - 'syncing', - 'failed' -] - - -class Connection(TypedDict): - id: str - entity_id: str - accounts: List[str] - source: ConnectionSourcesLiterals - status: ConnectionStatusesLiterals - error: Optional[ResourceError] - created_at: str - updated_at: str - last_synced_at: str - - -class ConnectionUpdateOpts(TypedDict): - status: Literal['syncing'] - - -class ConnectionResource(Resource): - def __init__(self, config: Configuration): - super(ConnectionResource, self).__init__(config.add_path('connections')) - - def get(self, _id: str) -> Connection: - return super(ConnectionResource, self)._get_with_id(_id) - - def list(self) -> List[Connection]: - return super(ConnectionResource, self)._list(None) - - def update(self, _id: str, opts: ConnectionUpdateOpts) -> Connection: - return super(ConnectionResource, self)._update_with_id(_id, opts) - - def get_public_account_tokens(self, _id: str) -> List[str]: - return super(ConnectionResource, self)._get_with_sub_path('{_id}/public_account_tokens'.format(_id=_id)) From 8171b47093a72e9519aa491b8e1bb47a6cf4a5a5 Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Thu, 4 Jan 2024 14:50:53 -0500 Subject: [PATCH 29/32] fixing spacing issue --- method/resources/Account.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/method/resources/Account.py b/method/resources/Account.py index d45d5fc..005cbf4 100644 --- a/method/resources/Account.py +++ b/method/resources/Account.py @@ -216,18 +216,18 @@ class TrendedDataItem(TypedDict): class AccountLiabilityStudentLoansDisbursement(AccountLiabilityLoan): - sequence: int - disbursed_at: Optional[str] - expected_payoff_date: Optional[str] - delinquent_status: Optional[str] - delinquent_amount: Optional[int] - delinquent_period: Optional[int] - delinquent_action: Optional[str] - delinquent_start_date: Optional[str] - delinquent_major_start_date: Optional[str] - delinquent_status_updated_at: Optional[str] - delinquent_history: Optional[List[DelinquencyHistoryItem]] - delinquent_action: Optional[List[TrendedDataItem]] + sequence: int + disbursed_at: Optional[str] + expected_payoff_date: Optional[str] + delinquent_status: Optional[str] + delinquent_amount: Optional[int] + delinquent_period: Optional[int] + delinquent_action: Optional[str] + delinquent_start_date: Optional[str] + delinquent_major_start_date: Optional[str] + delinquent_status_updated_at: Optional[str] + delinquent_history: Optional[List[DelinquencyHistoryItem]] + delinquent_action: Optional[List[TrendedDataItem]] class AccountLiabilityStudentLoans(AccountLiabilityLoan): From 3b2603deb96fc71a3f5970cf69a8f2366523a2f7 Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Thu, 4 Jan 2024 14:56:45 -0500 Subject: [PATCH 30/32] tried fixing indent again --- method/resources/Account.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/method/resources/Account.py b/method/resources/Account.py index 005cbf4..d45d5fc 100644 --- a/method/resources/Account.py +++ b/method/resources/Account.py @@ -216,18 +216,18 @@ class TrendedDataItem(TypedDict): class AccountLiabilityStudentLoansDisbursement(AccountLiabilityLoan): - sequence: int - disbursed_at: Optional[str] - expected_payoff_date: Optional[str] - delinquent_status: Optional[str] - delinquent_amount: Optional[int] - delinquent_period: Optional[int] - delinquent_action: Optional[str] - delinquent_start_date: Optional[str] - delinquent_major_start_date: Optional[str] - delinquent_status_updated_at: Optional[str] - delinquent_history: Optional[List[DelinquencyHistoryItem]] - delinquent_action: Optional[List[TrendedDataItem]] + sequence: int + disbursed_at: Optional[str] + expected_payoff_date: Optional[str] + delinquent_status: Optional[str] + delinquent_amount: Optional[int] + delinquent_period: Optional[int] + delinquent_action: Optional[str] + delinquent_start_date: Optional[str] + delinquent_major_start_date: Optional[str] + delinquent_status_updated_at: Optional[str] + delinquent_history: Optional[List[DelinquencyHistoryItem]] + delinquent_action: Optional[List[TrendedDataItem]] class AccountLiabilityStudentLoans(AccountLiabilityLoan): From b0e9403040e30b23429ed02978b5a916412fe09c Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Thu, 4 Jan 2024 15:13:25 -0500 Subject: [PATCH 31/32] fixed formatting throughout --- README.md | 2 +- method/resources/Account.py | 40 +++++++++++------------------ method/resources/AccountSync.py | 12 ++++----- method/resources/Bin.py | 5 +++- method/resources/Element.py | 20 ++++++++------- method/resources/Entity.py | 2 -- method/resources/Report.py | 12 +++++---- method/resources/SimulatePayment.py | 1 - method/resources/Transaction.py | 24 ++++++++--------- 9 files changed, 56 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index bc68c12..9901e04 100644 --- a/README.md +++ b/README.md @@ -417,4 +417,4 @@ report = method.reports.get('rpt_cj2mkA3hFyHT5') ```python report_csv = method.reports.download('rpt_cj2mkA3hFyHT5') -``` \ No newline at end of file +``` diff --git a/method/resources/Account.py b/method/resources/Account.py index d45d5fc..d952302 100644 --- a/method/resources/Account.py +++ b/method/resources/Account.py @@ -128,7 +128,6 @@ ] -# Typed Classes class AccountACH(TypedDict): routing: int number: int @@ -216,18 +215,18 @@ class TrendedDataItem(TypedDict): class AccountLiabilityStudentLoansDisbursement(AccountLiabilityLoan): - sequence: int - disbursed_at: Optional[str] - expected_payoff_date: Optional[str] - delinquent_status: Optional[str] - delinquent_amount: Optional[int] - delinquent_period: Optional[int] - delinquent_action: Optional[str] - delinquent_start_date: Optional[str] - delinquent_major_start_date: Optional[str] - delinquent_status_updated_at: Optional[str] - delinquent_history: Optional[List[DelinquencyHistoryItem]] - delinquent_action: Optional[List[TrendedDataItem]] + sequence: int + disbursed_at: Optional[str] + expected_payoff_date: Optional[str] + delinquent_status: Optional[str] + delinquent_amount: Optional[int] + delinquent_period: Optional[int] + delinquent_action: Optional[str] + delinquent_start_date: Optional[str] + delinquent_major_start_date: Optional[str] + delinquent_status_updated_at: Optional[str] + delinquent_history: Optional[List[DelinquencyHistoryItem]] + delinquent_action: Optional[List[TrendedDataItem]] class AccountLiabilityStudentLoans(AccountLiabilityLoan): @@ -503,19 +502,13 @@ def get_details(self, _id: str) -> AccountDetail: return super(AccountResource, self)._get_with_sub_path('{_id}/details'.format(_id=_id)) def bulk_sync(self, acc_ids: AccountCreateBulkSyncOpts) -> AccountCreateBulkSyncResponse: - return super(AccountResource, self)._create_with_subpath( - 'bulk_sync', - { acc_ids } - ) + return super(AccountResource, self)._create_with_subpath('bulk_sync',{ acc_ids }) def sync(self, _id: str) -> AccountSync: return super(AccountResource, self)._create_with_sub_path('{_id}/syncs'.format(_id=_id), {}) def bulk_sensitive(self, acc_ids: AccountCreateBulkSensitiveOpts) -> AccountCreateBulkSensitiveResponse: - return super(AccountResource, self)._create_with_sub_path( - 'bulk_sensitive', - { acc_ids } - ) + return super(AccountResource, self)._create_with_sub_path('bulk_sensitive',{ acc_ids }) def sensitive(self, _id: str) -> AccountSensitive: return super(AccountResource, self)._get_with_sub_path('{_id}/sensitive'.format(_id=_id)) @@ -527,7 +520,4 @@ def unenroll_auto_syncs(self, _id: str) -> Account: return super(AccountResource, self)._delete_with_sub_path('{_id}/sync_enrollment'.format(_id=_id)) def withdraw_consent(self, _id: str, data: AccountWithdrawConsentOpts = { 'type': 'withdraw', 'reason': 'holder_withdrew_consent' }) -> Account: - return super(AccountResource, self)._create_with_sub_path( - '{_id}/consent'.format(_id=_id), - data - ) + return super(AccountResource, self)._create_with_sub_path('{_id}/consent'.format(_id=_id), data) diff --git a/method/resources/AccountSync.py b/method/resources/AccountSync.py index d528bce..dba089e 100644 --- a/method/resources/AccountSync.py +++ b/method/resources/AccountSync.py @@ -7,12 +7,12 @@ class AccountSync(TypedDict): - id: str - acc_id: str - status: str - error: Optional[ResourceError] - created_at: str - updated_at: str + id: str + acc_id: str + status: str + error: Optional[ResourceError] + created_at: str + updated_at: str class AccountSyncCreateOpts(TypedDict): pass diff --git a/method/resources/Bin.py b/method/resources/Bin.py index c038f78..9bf7ce3 100644 --- a/method/resources/Bin.py +++ b/method/resources/Bin.py @@ -12,7 +12,10 @@ 'diners_club' ] -BinTypesLiterals = Literal['debit', 'credit'] +BinTypesLiterals = Literal[ + 'debit', + 'credit' +] class Bin(TypedDict): diff --git a/method/resources/Element.py b/method/resources/Element.py index 84995af..958a756 100644 --- a/method/resources/Element.py +++ b/method/resources/Element.py @@ -5,7 +5,9 @@ from method.resources.Account import Account -ElementTypesLiterals = Literal['link'] +ElementTypesLiterals = Literal[ + 'link' +] UserEventTypeLiterals = Literal[ @@ -64,16 +66,16 @@ class Element(TypedDict): class ElementUserEvent(TypedDict): - type: UserEventTypeLiterals - timestamp: str - metadata: Optional[Dict[str, any]] + type: UserEventTypeLiterals + timestamp: str + metadata: Optional[Dict[str, any]] class TokenSessionResult(TypedDict): - authenticated: bool - cxn_id: Optional[str] - accounts: List[str] - entity_id: Optional[str] - events: List[ElementUserEvent] + authenticated: bool + cxn_id: Optional[str] + accounts: List[str] + entity_id: Optional[str] + events: List[ElementUserEvent] class ElementExchangePublicAccountOpts(TypedDict): diff --git a/method/resources/Entity.py b/method/resources/Entity.py index af3418f..9f5c8b7 100644 --- a/method/resources/Entity.py +++ b/method/resources/Entity.py @@ -320,7 +320,6 @@ def create_manual_auth_session(self, _id: str, opts: EntityManualAuthOpts) -> En def update_manual_auth_session(self, _id: str, opts: EntityManualAuthOpts) -> EntityManualAuthResponse: return super(EntityResource, self)._update_with_sub_path('{_id}/manual_auth_session'.format(_id=_id), opts) - # TODO: Add create and update manual auth session def refresh_capabilities(self, _id: str) -> Entity: return super(EntityResource, self)._create_with_sub_path('{_id}/refresh_capabilities'.format(_id=_id), {}) @@ -330,7 +329,6 @@ def get_credit_score(self, _id: str) -> EntityQuestionResponse: def get_sensitive_fields(self, _id: str) -> EntitySensitiveResponse: return super(EntityResource, self)._get_with_sub_path('{_id}/sensitive'.format(_id=_id)) - # TODO: get sensitive fields def withdraw_consent(self, _id: str) -> Entity: return super(EntityResource, self)._create_with_sub_path( diff --git a/method/resources/Report.py b/method/resources/Report.py index 016e5fc..e8a65b1 100644 --- a/method/resources/Report.py +++ b/method/resources/Report.py @@ -9,14 +9,16 @@ 'payments.created.previous', 'payments.updated.current', 'payments.updated.previous', - 'ach.pull.upcoming', - 'ach.pull.previous', - 'ach.pull.nightly', - 'ach.reversals.nightly' + 'ach.pull.upcoming', + 'ach.pull.previous', + 'ach.pull.nightly', + 'ach.reversals.nightly' ] -ReportStatusesLiterals = Literal['completed'] +ReportStatusesLiterals = Literal[ + 'completed' +] class Report(TypedDict): diff --git a/method/resources/SimulatePayment.py b/method/resources/SimulatePayment.py index 22db3c5..ffe6f4b 100644 --- a/method/resources/SimulatePayment.py +++ b/method/resources/SimulatePayment.py @@ -11,7 +11,6 @@ class SimulatePaymentUpdateOpts(TypedDict): class SimulatePaymentResource(Resource): - def __init__(self, config: Configuration): super(SimulatePaymentResource, self).__init__(config.add_path('payments')) diff --git a/method/resources/Transaction.py b/method/resources/Transaction.py index 85170e1..7af515c 100644 --- a/method/resources/Transaction.py +++ b/method/resources/Transaction.py @@ -5,18 +5,18 @@ class Transaction(TypedDict): - id: str - acc_id: str - mcc: str - description: str - presentable_description: str - amount: str - currency: str - billing_amount: str - billing_currency: str - status: str - created_at: str - updated_at: str + id: str + acc_id: str + mcc: str + description: str + presentable_description: str + amount: str + currency: str + billing_amount: str + billing_currency: str + status: str + created_at: str + updated_at: str class TransactionResource(Resource): From 18bffd8916a174d110d9aec0db39601fe9a857b9 Mon Sep 17 00:00:00 2001 From: Mike Ossig Date: Thu, 4 Jan 2024 17:32:54 -0500 Subject: [PATCH 32/32] fixed path in Transaction --- method/resources/Transaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/method/resources/Transaction.py b/method/resources/Transaction.py index 7af515c..4c52c10 100644 --- a/method/resources/Transaction.py +++ b/method/resources/Transaction.py @@ -21,7 +21,7 @@ class Transaction(TypedDict): class TransactionResource(Resource): def __init__(self, config: Configuration): - super(TransactionResource, self).__init__(config.add_path('resource')) + super(TransactionResource, self).__init__(config.add_path('transactions')) def list(self) -> List[Transaction]: return super(TransactionResource, self)._list(None)