Skip to content

Commit eac0165

Browse files
authored
Merge pull request #63 from MethodFi/bilal/mthd-9409
2 parents f24e52f + 5c11f86 commit eac0165

File tree

21 files changed

+493
-110
lines changed

21 files changed

+493
-110
lines changed

method/method.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
from method.resources.HealthCheck import PingResponse, HealthCheckResource
1111
from method.resources.Simulate import SimulateResource
1212
from method.resources.Events import EventResource
13+
from method.resources.CardProduct import CardProductResource
14+
from method.resources.Opal import OpalResource
1315

1416
class Method:
1517
accounts: AccountResource
@@ -22,6 +24,8 @@ class Method:
2224
webhooks: WebhookResource
2325
healthcheck: HealthCheckResource
2426
simulate: SimulateResource
27+
card_products: CardProductResource
28+
opal: OpalResource
2529

2630
def __init__(self, opts: ConfigurationOpts = None, **kwargs: ConfigurationOpts):
2731
_opts: ConfigurationOpts = {**(opts or {}), **kwargs} # type: ignore
@@ -37,6 +41,8 @@ def __init__(self, opts: ConfigurationOpts = None, **kwargs: ConfigurationOpts):
3741
self.webhooks = WebhookResource(config)
3842
self.healthcheck = HealthCheckResource(config)
3943
self.simulate = SimulateResource(config)
40-
44+
self.card_products = CardProductResource(config)
45+
self.opal = OpalResource(config)
46+
4147
def ping(self) -> MethodResponse[PingResponse]:
4248
return self.healthcheck.retrieve()

method/resource.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ def finalize_response(self, request_start_time: Optional[int] = None, request_en
126126

127127
class RequestOpts(TypedDict):
128128
idempotency_key: Optional[str]
129+
prefer: Optional[str]
129130

130131

131132
class ResourceListOpts(TypedDict):
@@ -146,7 +147,7 @@ def __init__(self, config: Configuration):
146147
'Authorization': 'Bearer {token}'.format(token=config.api_key),
147148
'Content-Type': 'application/json',
148149
'User-Agent': 'Method-Python/v{version}'.format(version=version('method-python')),
149-
'method-version': '2024-04-04'
150+
'method-version': '2025-07-04'
150151
})
151152

152153
def _make_request(self, method: str, path: Optional[str] = None, data: Optional[Dict] = None, params: Optional[Dict] = None, headers: Optional[Dict] = None, raw: bool = False, download: bool = False) -> Union[MethodResponse[T], str]:
@@ -224,6 +225,8 @@ def _create(self, data: Dict, params: Optional[Dict] = None, request_opts: Optio
224225
headers = {}
225226
if request_opts and request_opts.get('idempotency_key'):
226227
headers['Idempotency-Key'] = request_opts.get('idempotency_key')
228+
if request_opts and request_opts.get('prefer'):
229+
headers['Prefer'] = request_opts.get('prefer')
227230
return self._make_request('POST', data=data, headers=headers, params=params)
228231

229232
@MethodError.catch

method/resources/Accounts/CardBrands.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,21 @@
66

77

88
class AccountCardBrandInfo(TypedDict):
9-
art_id: str
10-
url: str
11-
name: str
9+
id: str
10+
card_product_id: str
11+
description: str
12+
name: str
13+
issuer: str
14+
network: str
15+
type: Literal['specific', 'generic', 'in_review']
16+
url: str
1217

1318

1419
class AccountCardBrand(TypedDict):
1520
id: str
1621
account_id: str
17-
network: str
18-
issuer: str
19-
last4: str
2022
brands: List[AccountCardBrandInfo]
21-
status: Literal['completed', 'failed']
23+
status: Literal['completed', 'in_progress', 'failed']
2224
shared: bool
2325
source: Optional[Literal['method', 'network']]
2426
error: Optional[ResourceError]

method/resources/Accounts/Products.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class AccountProduct(TypedDict):
1717
status: AccountProductTypeStatusLiterals
1818
status_error: Optional[ResourceError]
1919
latest_request_id: str
20-
latest_successful_request_id: str
20+
latest_successful_request_id: Optional[str]
2121
is_subscribable: bool
2222
created_at: str
2323
updated_at: str
@@ -38,8 +38,5 @@ class AccountProductResource(Resource):
3838
def __init__(self, config: Configuration):
3939
super(AccountProductResource, self).__init__(config.add_path('products'))
4040

41-
def retrieve(self, prd_id: str) -> MethodResponse[AccountProduct]:
42-
return super(AccountProductResource, self)._get_with_id(prd_id)
43-
4441
def list(self) -> MethodResponse[AccountProductListResponse]:
4542
return super(AccountProductResource, self)._list()

method/resources/Accounts/Types.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,29 @@ class AccountLiabilityStudentLoans(AccountLiabilityBase):
193193
original_loan_amount: Optional[int]
194194
term_length: Optional[int]
195195

196+
AccountLiabilitySubTypesLiterals = Literal[
197+
'business',
198+
'unsecured',
199+
'lease',
200+
'loan',
201+
'heloc',
202+
'charge',
203+
'flexible_spending',
204+
'secured',
205+
'purchase',
206+
'note',
207+
'private',
208+
'federal',
209+
'rent'
210+
]
196211

197212
class AccountLiability(TypedDict):
198213
mch_id: str
199214
mask: Optional[str]
200215
ownership: Optional[AccountOwnershipLiterals]
201216
fingerprint: Optional[str]
202217
type: Optional[AccountLiabilityTypesLiterals]
218+
sub_type: Optional[AccountLiabilitySubTypesLiterals]
203219
name: Optional[str]
204220

205221

method/resources/CardProduct.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from typing import TypedDict, Optional, List, Literal
2+
3+
from method.resource import MethodResponse, Resource
4+
from method.configuration import Configuration
5+
from method.errors import ResourceError
6+
7+
8+
CardProductTypeLiterals = Literal[
9+
'specific',
10+
'generic',
11+
'in_review',
12+
]
13+
14+
class CardProductBrand(TypedDict):
15+
id: str
16+
description: str
17+
network: str
18+
default_image: str
19+
20+
21+
class CardProduct(TypedDict):
22+
id: str
23+
name: str
24+
issuer: str
25+
type: CardProductTypeLiterals
26+
brands: List[CardProductBrand]
27+
error: Optional[ResourceError]
28+
created_at: str
29+
updated_at: str
30+
31+
32+
class CardProductResource(Resource):
33+
def __init__(self, config: Configuration):
34+
super(CardProductResource, self).__init__(config.add_path('card_product'))
35+
36+
37+
def retrieve(self, prt_id: str) -> MethodResponse[CardProduct]:
38+
return super(CardProductResource, self)._get_with_id(prt_id)
39+

method/resources/Entities/Connect.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import TypedDict, Optional, Literal, List
22

3-
from method.resource import MethodResponse, Resource, ResourceListOpts
3+
from method.resource import MethodResponse, RequestOpts, Resource, ResourceListOpts
44
from method.configuration import Configuration
55
from method.errors import ResourceError
66

@@ -40,8 +40,8 @@ class EntityConnect(TypedDict):
4040
id: str
4141
status: EntityConnectResponseStatusLiterals
4242
accounts: Optional[List[str]]
43-
requested_products: Optional[List[str]]
44-
requested_subscriptions: Optional[List[str]]
43+
requested_products: List[AccountProductsEligibleForAutomaticExecutionLiteral]
44+
requested_subscriptions: List[AccountSubscriptionsEligibleForAutomaticExecutionLiteral]
4545
error: Optional[ResourceError]
4646
created_at: str
4747
updated_at: str
@@ -76,7 +76,8 @@ def list(
7676
def create(
7777
self,
7878
opts: ConnectCreateOpts = {},
79-
params: Optional[ConnectExpandOpts] = None
79+
params: Optional[ConnectExpandOpts] = None,
80+
request_opts: Optional[RequestOpts] = None
8081
) -> MethodResponse[EntityConnect]:
81-
return super(EntityConnectResource, self)._create(data=opts, params=params)
82+
return super(EntityConnectResource, self)._create(data=opts, params=params, request_opts=request_opts)
8283

method/resources/Entities/Products.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class EntityProduct(TypedDict):
1717
status: EntityProductTypeStatusLiterals
1818
status_error: Optional[ResourceError]
1919
latest_request_id: str
20-
latest_successful_request_id: str
20+
latest_successful_request_id: Optional[str]
2121
is_subscribable: bool
2222
created_at: str
2323
updated_at: str
@@ -35,8 +35,5 @@ class EntityProductResource(Resource):
3535
def __init__(self, config: Configuration):
3636
super(EntityProductResource, self).__init__(config.add_path('products'))
3737

38-
def retrieve(self, prd_id: str) -> MethodResponse[EntityProduct]:
39-
return super(EntityProductResource, self)._get_with_id(prd_id)
40-
4138
def list(self) -> MethodResponse[EntityProductListResponse]:
4239
return super(EntityProductResource, self)._list()

method/resources/Opal/Opal.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from method.resource import Resource
2+
from method.configuration import Configuration
3+
from method.resources.Opal.Token import OpalTokenResource
4+
5+
6+
class OpalResource(Resource):
7+
token: OpalTokenResource
8+
9+
def __init__(self, config: Configuration):
10+
_config = config.add_path('opal')
11+
super(OpalResource, self).__init__(_config)
12+
self.token = OpalTokenResource(_config)

method/resources/Opal/Token.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
from typing import TypedDict, Optional, Literal, List, Dict
2+
3+
from method.resource import MethodResponse, Resource
4+
from method.configuration import Configuration
5+
6+
OpalModesLiterals = Literal[
7+
'identity_verification',
8+
'connect',
9+
'card_connect',
10+
'account_verification',
11+
'transactions'
12+
]
13+
14+
15+
SkipPIILiterals = Literal[
16+
'name',
17+
'dob',
18+
'address',
19+
'ssn_4'
20+
]
21+
22+
23+
AccountFiltersAccountTypesLiterals = Literal[
24+
'credit_card',
25+
'auto_loan',
26+
'mortgage',
27+
'personal_loan',
28+
'student_loan'
29+
]
30+
31+
32+
SelectionTypeLiterals = Literal['single', 'multiple', 'all']
33+
34+
35+
class OpalAccountFiltersInclude(TypedDict):
36+
account_types: List[AccountFiltersAccountTypesLiterals]
37+
38+
39+
class OpalAccountFiltersExclude(TypedDict):
40+
account_types: List[AccountFiltersAccountTypesLiterals]
41+
mch_ids: List[str]
42+
unverified_account_numbers: bool
43+
44+
45+
class ConnectAccountFilters(TypedDict):
46+
include: OpalAccountFiltersInclude
47+
exclude: OpalAccountFiltersExclude
48+
49+
50+
class CardConnectAccountFiltersExclude(TypedDict):
51+
mch_ids: List[str]
52+
unverified_account_numbers: bool
53+
54+
55+
class CardConnectAccountFilters(TypedDict):
56+
exclude: CardConnectAccountFiltersExclude
57+
58+
59+
class OpalIdentityVerificationCreateOpts(TypedDict):
60+
skip_pii: List[SkipPIILiterals]
61+
62+
63+
class OpalConnectCreateOpts(TypedDict):
64+
skip_pii: List[SkipPIILiterals]
65+
selection_type: SelectionTypeLiterals
66+
account_filters: ConnectAccountFilters
67+
68+
69+
class OpalCardConnectCreateOpts(TypedDict):
70+
skip_pii: List[SkipPIILiterals]
71+
selection_type: SelectionTypeLiterals
72+
account_filters: CardConnectAccountFilters
73+
74+
75+
class OpalAccountVerificationCreateOpts(TypedDict):
76+
account_id: str
77+
78+
79+
class OpalTransactionsCreateOpts(TypedDict):
80+
transactions: Dict[str, any]
81+
82+
83+
class OpalTokenCreateOpts(TypedDict):
84+
mode: OpalModesLiterals
85+
entity_id: str
86+
identity_verification: Optional[OpalIdentityVerificationCreateOpts]
87+
connect: Optional[OpalConnectCreateOpts]
88+
card_connect: Optional[OpalCardConnectCreateOpts]
89+
account_verification: Optional[OpalAccountVerificationCreateOpts]
90+
transactions: Optional[OpalTransactionsCreateOpts]
91+
92+
93+
class OpalToken(TypedDict):
94+
token: str
95+
valid_until: str
96+
session_id: str
97+
98+
99+
class OpalTokenResource(Resource):
100+
def __init__(self, config: Configuration):
101+
super(OpalTokenResource, self).__init__(config.add_path('token'))
102+
103+
def create(self, opts: OpalTokenCreateOpts) -> MethodResponse[OpalToken]:
104+
return super(OpalTokenResource, self)._create(opts)

0 commit comments

Comments
 (0)