1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-08-06 14:05:20 +02:00

Plaid sync domain improvements (#2267)
Some checks are pending
Publish Docker image / ci (push) Waiting to run
Publish Docker image / Build docker image (push) Blocked by required conditions

Breaks our Plaid sync process out into more manageable classes. Notably, this moves the sync process to a distinct, 2-step flow:

1. Import stage - we first make API calls and import Plaid data to "mirror" tables
2. Processing stage - read the raw data, apply business rules, build internal domain models and sync balances

This provides several benefits:

- Plaid syncs can now be "replayed" without fetching API data again
- Mirror tables provide better audit and debugging capabilities
- Eliminates the "all or nothing" sync behavior that is currently in place, which is brittle
This commit is contained in:
Zach Gollwitzer 2025-05-23 18:58:22 -04:00 committed by GitHub
parent 5c82af0e8c
commit 03a146222d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
72 changed files with 3763 additions and 706 deletions

View file

@ -0,0 +1,124 @@
---
http_interactions:
- request:
method: post
uri: https://sandbox.plaid.com/sandbox/public_token/create
body:
encoding: UTF-8
string: '{"institution_id":"ins_109508","initial_products":["transactions","investments","liabilities"],"options":{"override_username":"custom_test"}}'
headers:
Content-Type:
- application/json
User-Agent:
- Plaid Ruby v38.0.0
Accept:
- application/json
Plaid-Client-Id:
- "<PLAID_CLIENT_ID>"
Plaid-Version:
- '2020-09-14'
Plaid-Secret:
- "<PLAID_SECRET>"
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 19 May 2025 17:24:03 GMT
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '110'
Connection:
- keep-alive
Plaid-Version:
- '2020-09-14'
Vary:
- Accept-Encoding
X-Envoy-Upstream-Service-Time:
- '2892'
X-Envoy-Decorator-Operation:
- default.svc-apiv2:8080/*
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
X-Xss-Protection:
- 1; mode=block
body:
encoding: ASCII-8BIT
string: |-
{
"public_token": "public-sandbox-0463cb9d-8bdb-4e01-9b33-243e1370623c",
"request_id": "FaSopSLAyHsZM9O"
}
recorded_at: Mon, 19 May 2025 17:24:03 GMT
- request:
method: post
uri: https://sandbox.plaid.com/item/public_token/exchange
body:
encoding: UTF-8
string: '{"public_token":"public-sandbox-0463cb9d-8bdb-4e01-9b33-243e1370623c"}'
headers:
Content-Type:
- application/json
User-Agent:
- Plaid Ruby v38.0.0
Accept:
- application/json
Plaid-Client-Id:
- "<PLAID_CLIENT_ID>"
Plaid-Version:
- '2020-09-14'
Plaid-Secret:
- "<PLAID_SECRET>"
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 19 May 2025 17:24:03 GMT
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '164'
Connection:
- keep-alive
Plaid-Version:
- '2020-09-14'
Vary:
- Accept-Encoding
X-Envoy-Upstream-Service-Time:
- '171'
X-Envoy-Decorator-Operation:
- default.svc-apiv2:8080/*
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
X-Xss-Protection:
- 1; mode=block
body:
encoding: ASCII-8BIT
string: |-
{
"access_token": "access-sandbox-0af2c971-41a6-4fc5-a97d-f2b27ab0a648",
"item_id": "n7XKpjRmDkHENymaBw7rU71wxQnrW4i6DDrQP",
"request_id": "2e1nOnm2CoOXVcH"
}
recorded_at: Mon, 19 May 2025 17:24:03 GMT
recorded_with: VCR 6.3.1

View file

@ -0,0 +1,124 @@
---
http_interactions:
- request:
method: post
uri: https://sandbox.plaid.com/sandbox/public_token/create
body:
encoding: UTF-8
string: '{"institution_id":"ins_109508","initial_products":["transactions","investments","liabilities"],"options":{"override_username":"custom_test"}}'
headers:
Content-Type:
- application/json
User-Agent:
- Plaid Ruby v38.0.0
Accept:
- application/json
Plaid-Client-Id:
- "<PLAID_CLIENT_ID>"
Plaid-Version:
- '2020-09-14'
Plaid-Secret:
- "<PLAID_SECRET>"
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 19 May 2025 17:24:09 GMT
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '110'
Connection:
- keep-alive
Plaid-Version:
- '2020-09-14'
Vary:
- Accept-Encoding
X-Envoy-Upstream-Service-Time:
- '3086'
X-Envoy-Decorator-Operation:
- default.svc-apiv2:8080/*
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
X-Xss-Protection:
- 1; mode=block
body:
encoding: ASCII-8BIT
string: |-
{
"public_token": "public-sandbox-29a5644f-001d-4bf5-abae-d26ecf8ee211",
"request_id": "6dz2Xo7zoyT9W9R"
}
recorded_at: Mon, 19 May 2025 17:24:09 GMT
- request:
method: post
uri: https://sandbox.plaid.com/item/public_token/exchange
body:
encoding: UTF-8
string: '{"public_token":"public-sandbox-29a5644f-001d-4bf5-abae-d26ecf8ee211"}'
headers:
Content-Type:
- application/json
User-Agent:
- Plaid Ruby v38.0.0
Accept:
- application/json
Plaid-Client-Id:
- "<PLAID_CLIENT_ID>"
Plaid-Version:
- '2020-09-14'
Plaid-Secret:
- "<PLAID_SECRET>"
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 19 May 2025 17:24:09 GMT
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '164'
Connection:
- keep-alive
Plaid-Version:
- '2020-09-14'
Vary:
- Accept-Encoding
X-Envoy-Upstream-Service-Time:
- '152'
X-Envoy-Decorator-Operation:
- default.svc-apiv2:8080/*
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
X-Xss-Protection:
- 1; mode=block
body:
encoding: ASCII-8BIT
string: |-
{
"access_token": "access-sandbox-fb7bb5da-e3e2-464e-8644-4eeafbf6541f",
"item_id": "bd9d3lAbjqhWyRz7bl61s9R7npPJ87HVzAyvn",
"request_id": "GqA99rziFZduKYg"
}
recorded_at: Mon, 19 May 2025 17:24:09 GMT
recorded_with: VCR 6.3.1

View file

@ -0,0 +1,106 @@
---
http_interactions:
- request:
method: post
uri: https://sandbox.plaid.com/item/get
body:
encoding: UTF-8
string: '{"access_token":"access-sandbox-0af2c971-41a6-4fc5-a97d-f2b27ab0a648"}'
headers:
Content-Type:
- application/json
User-Agent:
- Plaid Ruby v38.0.0
Accept:
- application/json
Plaid-Client-Id:
- "<PLAID_CLIENT_ID>"
Plaid-Version:
- '2020-09-14'
Plaid-Secret:
- "<PLAID_SECRET>"
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 19 May 2025 17:24:03 GMT
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '1050'
Connection:
- keep-alive
Plaid-Version:
- '2020-09-14'
Vary:
- Accept-Encoding
X-Envoy-Upstream-Service-Time:
- '157'
X-Envoy-Decorator-Operation:
- default.svc-apiv2:8080/*
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
X-Xss-Protection:
- 1; mode=block
body:
encoding: ASCII-8BIT
string: |-
{
"item": {
"available_products": [
"assets",
"auth",
"balance",
"credit_details",
"identity",
"identity_match",
"income",
"income_verification",
"recurring_transactions",
"signal",
"statements"
],
"billed_products": [
"investments",
"liabilities",
"transactions"
],
"consent_expiration_time": null,
"created_at": "2025-05-19T17:24:00Z",
"error": null,
"institution_id": "ins_109508",
"institution_name": "First Platypus Bank",
"item_id": "n7XKpjRmDkHENymaBw7rU71wxQnrW4i6DDrQP",
"products": [
"investments",
"liabilities",
"transactions"
],
"update_type": "background",
"webhook": ""
},
"request_id": "dpcY8geAZ93oxJm",
"status": {
"investments": {
"last_failed_update": null,
"last_successful_update": "2025-05-19T17:24:01.861Z"
},
"last_webhook": null,
"transactions": {
"last_failed_update": null,
"last_successful_update": null
}
}
}
recorded_at: Mon, 19 May 2025 17:24:03 GMT
recorded_with: VCR 6.3.1

View file

@ -0,0 +1,160 @@
---
http_interactions:
- request:
method: post
uri: https://sandbox.plaid.com/accounts/get
body:
encoding: UTF-8
string: '{"access_token":"access-sandbox-0af2c971-41a6-4fc5-a97d-f2b27ab0a648"}'
headers:
Content-Type:
- application/json
User-Agent:
- Plaid Ruby v38.0.0
Accept:
- application/json
Plaid-Client-Id:
- "<PLAID_CLIENT_ID>"
Plaid-Version:
- '2020-09-14'
Plaid-Secret:
- "<PLAID_SECRET>"
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 19 May 2025 17:24:04 GMT
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '2578'
Connection:
- keep-alive
Plaid-Version:
- '2020-09-14'
Vary:
- Accept-Encoding
X-Envoy-Upstream-Service-Time:
- '191'
X-Envoy-Decorator-Operation:
- default.svc-apiv2:8080/*
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
X-Xss-Protection:
- 1; mode=block
body:
encoding: ASCII-8BIT
string: |-
{
"accounts": [
{
"account_id": "vor45kgbDjfqa1BMD8QRU4om8adWNWtqbzQJe",
"balances": {
"available": 8000,
"current": 10000,
"iso_currency_code": "USD",
"limit": null,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "1122",
"name": "Test Brokerage Account",
"official_name": "Plaid brokerage",
"subtype": "brokerage",
"type": "investment"
},
{
"account_id": "RperV9wJMNiDWKljGMkPCkwDGJb7q7FaNlVMp",
"balances": {
"available": 9372.38,
"current": 1000,
"iso_currency_code": "USD",
"limit": 10500,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "1219",
"name": "Test Credit Card Account",
"official_name": "Plaid credit card",
"subtype": "credit card",
"type": "credit"
},
{
"account_id": "9mvxVZRW7LUD67QbEBm1CPZ6XlqkmkF4oGNBo",
"balances": {
"available": 10000,
"current": 10000,
"iso_currency_code": "USD",
"limit": null,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "4243",
"name": "Test Depository Account",
"official_name": "Plaid checking",
"subtype": "checking",
"type": "depository"
},
{
"account_id": "6Gwzm7nJ6ZU4VbqEyKzZszyPQ8keRet8Q97k7",
"balances": {
"available": 15000,
"current": 15000,
"iso_currency_code": "USD",
"limit": null,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "9572",
"name": "Test Student Loan Account",
"official_name": "Plaid student",
"subtype": "student",
"type": "loan"
}
],
"item": {
"available_products": [
"assets",
"auth",
"balance",
"credit_details",
"identity",
"identity_match",
"income",
"income_verification",
"recurring_transactions",
"signal",
"statements"
],
"billed_products": [
"investments",
"liabilities",
"transactions"
],
"consent_expiration_time": null,
"error": null,
"institution_id": "ins_109508",
"institution_name": "First Platypus Bank",
"item_id": "n7XKpjRmDkHENymaBw7rU71wxQnrW4i6DDrQP",
"products": [
"investments",
"liabilities",
"transactions"
],
"update_type": "background",
"webhook": ""
},
"request_id": "EWD5MMMYV0o9cZ0"
}
recorded_at: Mon, 19 May 2025 17:24:04 GMT
recorded_with: VCR 6.3.1

View file

@ -0,0 +1,570 @@
---
http_interactions:
- request:
method: post
uri: https://sandbox.plaid.com/investments/holdings/get
body:
encoding: UTF-8
string: '{"access_token":"access-sandbox-0af2c971-41a6-4fc5-a97d-f2b27ab0a648"}'
headers:
Content-Type:
- application/json
User-Agent:
- Plaid Ruby v38.0.0
Accept:
- application/json
Plaid-Client-Id:
- "<PLAID_CLIENT_ID>"
Plaid-Version:
- '2020-09-14'
Plaid-Secret:
- "<PLAID_SECRET>"
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 19 May 2025 17:24:05 GMT
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '6199'
Connection:
- keep-alive
Plaid-Version:
- '2020-09-14'
Vary:
- Accept-Encoding
X-Envoy-Upstream-Service-Time:
- '324'
X-Envoy-Decorator-Operation:
- default.svc-apiv2:8080/*
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
X-Xss-Protection:
- 1; mode=block
body:
encoding: ASCII-8BIT
string: |-
{
"accounts": [
{
"account_id": "vor45kgbDjfqa1BMD8QRU4om8adWNWtqbzQJe",
"balances": {
"available": 8000,
"current": 10000,
"iso_currency_code": "USD",
"limit": null,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "1122",
"name": "Test Brokerage Account",
"official_name": "Plaid brokerage",
"subtype": "brokerage",
"type": "investment"
},
{
"account_id": "RperV9wJMNiDWKljGMkPCkwDGJb7q7FaNlVMp",
"balances": {
"available": 9372.38,
"current": 1000,
"iso_currency_code": "USD",
"limit": 10500,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "1219",
"name": "Test Credit Card Account",
"official_name": "Plaid credit card",
"subtype": "credit card",
"type": "credit"
},
{
"account_id": "9mvxVZRW7LUD67QbEBm1CPZ6XlqkmkF4oGNBo",
"balances": {
"available": 10000,
"current": 10000,
"iso_currency_code": "USD",
"limit": null,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "4243",
"name": "Test Depository Account",
"official_name": "Plaid checking",
"subtype": "checking",
"type": "depository"
},
{
"account_id": "6Gwzm7nJ6ZU4VbqEyKzZszyPQ8keRet8Q97k7",
"balances": {
"available": 15000,
"current": 15000,
"iso_currency_code": "USD",
"limit": null,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "9572",
"name": "Test Student Loan Account",
"official_name": "Plaid student",
"subtype": "student",
"type": "loan"
}
],
"holdings": [
{
"account_id": "vor45kgbDjfqa1BMD8QRU4om8adWNWtqbzQJe",
"cost_basis": 2000,
"institution_price": 100,
"institution_price_as_of": "2025-05-08",
"institution_price_datetime": null,
"institution_value": 2000,
"iso_currency_code": "USD",
"quantity": 20,
"security_id": "xnL3QM3Ax4fP9lVmNLblTDaMkVMqN3fmxrXRd",
"unofficial_currency_code": null,
"vested_quantity": null,
"vested_value": null
},
{
"account_id": "vor45kgbDjfqa1BMD8QRU4om8adWNWtqbzQJe",
"cost_basis": 3000,
"institution_price": 1,
"institution_price_as_of": "2025-05-08",
"institution_price_datetime": null,
"institution_value": 3000,
"iso_currency_code": "USD",
"quantity": 3000,
"security_id": "EDRxkXxj7mtj8EzBBxllUqpy7KyNDBugoZrMX",
"unofficial_currency_code": null,
"vested_quantity": null,
"vested_value": null
},
{
"account_id": "vor45kgbDjfqa1BMD8QRU4om8adWNWtqbzQJe",
"cost_basis": 5000,
"institution_price": 1,
"institution_price_as_of": "2025-05-08",
"institution_price_datetime": null,
"institution_value": 5000,
"iso_currency_code": "USD",
"quantity": 5000,
"security_id": "7Dv19k16PZtEaexk6EZyFxP95o9ynrF4REalG",
"unofficial_currency_code": null,
"vested_quantity": null,
"vested_value": null
}
],
"item": {
"available_products": [
"assets",
"auth",
"balance",
"credit_details",
"identity",
"identity_match",
"income",
"income_verification",
"recurring_transactions",
"signal",
"statements"
],
"billed_products": [
"investments",
"liabilities",
"transactions"
],
"consent_expiration_time": null,
"error": null,
"institution_id": "ins_109508",
"institution_name": "First Platypus Bank",
"item_id": "n7XKpjRmDkHENymaBw7rU71wxQnrW4i6DDrQP",
"products": [
"investments",
"liabilities",
"transactions"
],
"update_type": "background",
"webhook": ""
},
"request_id": "uRzq5c4Y37RCNNj",
"securities": [
{
"close_price": 1,
"close_price_as_of": "2025-04-28",
"cusip": null,
"fixed_income": null,
"industry": "Investment Trusts or Mutual Funds",
"institution_id": null,
"institution_security_id": null,
"is_cash_equivalent": true,
"isin": null,
"iso_currency_code": "USD",
"market_identifier_code": null,
"name": "Vanguard Money Market Reserves - Federal Money Market Fd USD MNT",
"option_contract": null,
"proxy_security_id": null,
"sector": "Miscellaneous",
"security_id": "7Dv19k16PZtEaexk6EZyFxP95o9ynrF4REalG",
"sedol": "2571678",
"ticker_symbol": "VMFXX",
"type": "mutual fund",
"unofficial_currency_code": null,
"update_datetime": null
},
{
"close_price": 1,
"close_price_as_of": "2025-05-18",
"cusip": null,
"fixed_income": null,
"industry": null,
"institution_id": null,
"institution_security_id": null,
"is_cash_equivalent": true,
"isin": null,
"iso_currency_code": "USD",
"market_identifier_code": null,
"name": "U S Dollar",
"option_contract": null,
"proxy_security_id": null,
"sector": null,
"security_id": "EDRxkXxj7mtj8EzBBxllUqpy7KyNDBugoZrMX",
"sedol": null,
"ticker_symbol": "CUR:USD",
"type": "cash",
"unofficial_currency_code": null,
"update_datetime": null
},
{
"close_price": 211.26,
"close_price_as_of": "2025-05-16",
"cusip": null,
"fixed_income": null,
"industry": "Telecommunications Equipment",
"institution_id": null,
"institution_security_id": null,
"is_cash_equivalent": false,
"isin": null,
"iso_currency_code": "USD",
"market_identifier_code": "XNAS",
"name": "Apple Inc",
"option_contract": null,
"proxy_security_id": null,
"sector": "Electronic Technology",
"security_id": "xnL3QM3Ax4fP9lVmNLblTDaMkVMqN3fmxrXRd",
"sedol": "2046251",
"ticker_symbol": "AAPL",
"type": "equity",
"unofficial_currency_code": null,
"update_datetime": null
}
]
}
recorded_at: Mon, 19 May 2025 17:24:05 GMT
- request:
method: post
uri: https://sandbox.plaid.com/investments/transactions/get
body:
encoding: UTF-8
string: '{"access_token":"access-sandbox-0af2c971-41a6-4fc5-a97d-f2b27ab0a648","start_date":"2023-05-20","end_date":"2025-05-19","options":{"offset":0}}'
headers:
Content-Type:
- application/json
User-Agent:
- Plaid Ruby v38.0.0
Accept:
- application/json
Plaid-Client-Id:
- "<PLAID_CLIENT_ID>"
Plaid-Version:
- '2020-09-14'
Plaid-Secret:
- "<PLAID_SECRET>"
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 19 May 2025 17:24:05 GMT
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '6964'
Connection:
- keep-alive
Plaid-Version:
- '2020-09-14'
Vary:
- Accept-Encoding
X-Envoy-Upstream-Service-Time:
- '334'
X-Envoy-Decorator-Operation:
- default.svc-apiv2:8080/*
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
X-Xss-Protection:
- 1; mode=block
body:
encoding: ASCII-8BIT
string: |-
{
"accounts": [
{
"account_id": "vor45kgbDjfqa1BMD8QRU4om8adWNWtqbzQJe",
"balances": {
"available": 8000,
"current": 10000,
"iso_currency_code": "USD",
"limit": null,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "1122",
"name": "Test Brokerage Account",
"official_name": "Plaid brokerage",
"subtype": "brokerage",
"type": "investment"
},
{
"account_id": "RperV9wJMNiDWKljGMkPCkwDGJb7q7FaNlVMp",
"balances": {
"available": 9372.38,
"current": 1000,
"iso_currency_code": "USD",
"limit": 10500,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "1219",
"name": "Test Credit Card Account",
"official_name": "Plaid credit card",
"subtype": "credit card",
"type": "credit"
},
{
"account_id": "9mvxVZRW7LUD67QbEBm1CPZ6XlqkmkF4oGNBo",
"balances": {
"available": 10000,
"current": 10000,
"iso_currency_code": "USD",
"limit": null,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "4243",
"name": "Test Depository Account",
"official_name": "Plaid checking",
"subtype": "checking",
"type": "depository"
},
{
"account_id": "6Gwzm7nJ6ZU4VbqEyKzZszyPQ8keRet8Q97k7",
"balances": {
"available": 15000,
"current": 15000,
"iso_currency_code": "USD",
"limit": null,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "9572",
"name": "Test Student Loan Account",
"official_name": "Plaid student",
"subtype": "student",
"type": "loan"
}
],
"investment_transactions": [
{
"account_id": "vor45kgbDjfqa1BMD8QRU4om8adWNWtqbzQJe",
"amount": -5000,
"cancel_transaction_id": null,
"date": "2025-05-03",
"fees": 0,
"investment_transaction_id": "eBqoazM4XkiXx5gZbmD7UKRZ3jE3ABUreq4R1",
"iso_currency_code": "USD",
"name": "retirement contribution",
"price": 1,
"quantity": -5000,
"security_id": "EDRxkXxj7mtj8EzBBxllUqpy7KyNDBugoZrMX",
"subtype": "contribution",
"type": "cash",
"unofficial_currency_code": null
},
{
"account_id": "vor45kgbDjfqa1BMD8QRU4om8adWNWtqbzQJe",
"amount": 5000,
"cancel_transaction_id": null,
"date": "2025-05-03",
"fees": 0,
"investment_transaction_id": "QLeKVkpQM4ck1qMRGp6PUPp7obKowGtwRN547",
"iso_currency_code": "USD",
"name": "buy money market shares with contribution cash",
"price": 1,
"quantity": 5000,
"security_id": "7Dv19k16PZtEaexk6EZyFxP95o9ynrF4REalG",
"subtype": "contribution",
"type": "buy",
"unofficial_currency_code": null
},
{
"account_id": "vor45kgbDjfqa1BMD8QRU4om8adWNWtqbzQJe",
"amount": 2000,
"cancel_transaction_id": null,
"date": "2025-05-02",
"fees": 0,
"investment_transaction_id": "ZnxNgJEwM1ig5476JqZxUKeJLXNLnMUe9o6Al",
"iso_currency_code": "USD",
"name": "buy AAPL stock",
"price": 100,
"quantity": 20,
"security_id": "xnL3QM3Ax4fP9lVmNLblTDaMkVMqN3fmxrXRd",
"subtype": "buy",
"type": "buy",
"unofficial_currency_code": null
},
{
"account_id": "vor45kgbDjfqa1BMD8QRU4om8adWNWtqbzQJe",
"amount": -5000,
"cancel_transaction_id": null,
"date": "2025-05-01",
"fees": 0,
"investment_transaction_id": "MQ1Awmg943IKyWlQjRXgUqXrxD6xo3CLGjJw1",
"iso_currency_code": "USD",
"name": "Deposit cash into brokerage account",
"price": 1,
"quantity": -5000,
"security_id": "EDRxkXxj7mtj8EzBBxllUqpy7KyNDBugoZrMX",
"subtype": "deposit",
"type": "cash",
"unofficial_currency_code": null
}
],
"item": {
"available_products": [
"assets",
"auth",
"balance",
"credit_details",
"identity",
"identity_match",
"income",
"income_verification",
"recurring_transactions",
"signal",
"statements"
],
"billed_products": [
"investments",
"liabilities",
"transactions"
],
"consent_expiration_time": null,
"error": null,
"institution_id": "ins_109508",
"institution_name": "First Platypus Bank",
"item_id": "n7XKpjRmDkHENymaBw7rU71wxQnrW4i6DDrQP",
"products": [
"investments",
"liabilities",
"transactions"
],
"update_type": "background",
"webhook": ""
},
"request_id": "dTc49uKiBZWzxHS",
"securities": [
{
"close_price": 1,
"close_price_as_of": "2025-04-28",
"cusip": null,
"fixed_income": null,
"industry": "Investment Trusts or Mutual Funds",
"institution_id": null,
"institution_security_id": null,
"is_cash_equivalent": true,
"isin": null,
"iso_currency_code": "USD",
"market_identifier_code": null,
"name": "Vanguard Money Market Reserves - Federal Money Market Fd USD MNT",
"option_contract": null,
"proxy_security_id": null,
"sector": "Miscellaneous",
"security_id": "7Dv19k16PZtEaexk6EZyFxP95o9ynrF4REalG",
"sedol": "2571678",
"ticker_symbol": "VMFXX",
"type": "mutual fund",
"unofficial_currency_code": null,
"update_datetime": null
},
{
"close_price": 1,
"close_price_as_of": "2025-05-18",
"cusip": null,
"fixed_income": null,
"industry": null,
"institution_id": null,
"institution_security_id": null,
"is_cash_equivalent": true,
"isin": null,
"iso_currency_code": "USD",
"market_identifier_code": null,
"name": "U S Dollar",
"option_contract": null,
"proxy_security_id": null,
"sector": null,
"security_id": "EDRxkXxj7mtj8EzBBxllUqpy7KyNDBugoZrMX",
"sedol": null,
"ticker_symbol": "CUR:USD",
"type": "cash",
"unofficial_currency_code": null,
"update_datetime": null
},
{
"close_price": 211.26,
"close_price_as_of": "2025-05-16",
"cusip": null,
"fixed_income": null,
"industry": "Telecommunications Equipment",
"institution_id": null,
"institution_security_id": null,
"is_cash_equivalent": false,
"isin": null,
"iso_currency_code": "USD",
"market_identifier_code": "XNAS",
"name": "Apple Inc",
"option_contract": null,
"proxy_security_id": null,
"sector": "Electronic Technology",
"security_id": "xnL3QM3Ax4fP9lVmNLblTDaMkVMqN3fmxrXRd",
"sedol": "2046251",
"ticker_symbol": "AAPL",
"type": "equity",
"unofficial_currency_code": null,
"update_datetime": null
}
],
"total_investment_transactions": 4
}
recorded_at: Mon, 19 May 2025 17:24:05 GMT
recorded_with: VCR 6.3.1

View file

@ -0,0 +1,236 @@
---
http_interactions:
- request:
method: post
uri: https://sandbox.plaid.com/liabilities/get
body:
encoding: UTF-8
string: '{"access_token":"access-sandbox-0af2c971-41a6-4fc5-a97d-f2b27ab0a648"}'
headers:
Content-Type:
- application/json
User-Agent:
- Plaid Ruby v38.0.0
Accept:
- application/json
Plaid-Client-Id:
- "<PLAID_CLIENT_ID>"
Plaid-Version:
- '2020-09-14'
Plaid-Secret:
- "<PLAID_SECRET>"
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 19 May 2025 17:24:04 GMT
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '4907'
Connection:
- keep-alive
Plaid-Version:
- '2020-09-14'
Vary:
- Accept-Encoding
X-Envoy-Upstream-Service-Time:
- '253'
X-Envoy-Decorator-Operation:
- default.svc-apiv2:8080/*
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
X-Xss-Protection:
- 1; mode=block
body:
encoding: ASCII-8BIT
string: |-
{
"accounts": [
{
"account_id": "vor45kgbDjfqa1BMD8QRU4om8adWNWtqbzQJe",
"balances": {
"available": 8000,
"current": 10000,
"iso_currency_code": "USD",
"limit": null,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "1122",
"name": "Test Brokerage Account",
"official_name": "Plaid brokerage",
"subtype": "brokerage",
"type": "investment"
},
{
"account_id": "RperV9wJMNiDWKljGMkPCkwDGJb7q7FaNlVMp",
"balances": {
"available": 9372.38,
"current": 1000,
"iso_currency_code": "USD",
"limit": 10500,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "1219",
"name": "Test Credit Card Account",
"official_name": "Plaid credit card",
"subtype": "credit card",
"type": "credit"
},
{
"account_id": "9mvxVZRW7LUD67QbEBm1CPZ6XlqkmkF4oGNBo",
"balances": {
"available": 10000,
"current": 10000,
"iso_currency_code": "USD",
"limit": null,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "4243",
"name": "Test Depository Account",
"official_name": "Plaid checking",
"subtype": "checking",
"type": "depository"
},
{
"account_id": "6Gwzm7nJ6ZU4VbqEyKzZszyPQ8keRet8Q97k7",
"balances": {
"available": 15000,
"current": 15000,
"iso_currency_code": "USD",
"limit": null,
"unofficial_currency_code": null
},
"holder_category": "personal",
"mask": "9572",
"name": "Test Student Loan Account",
"official_name": "Plaid student",
"subtype": "student",
"type": "loan"
}
],
"item": {
"available_products": [
"assets",
"auth",
"balance",
"credit_details",
"identity",
"identity_match",
"income",
"income_verification",
"recurring_transactions",
"signal",
"statements"
],
"billed_products": [
"investments",
"liabilities",
"transactions"
],
"consent_expiration_time": null,
"error": null,
"institution_id": "ins_109508",
"institution_name": "First Platypus Bank",
"item_id": "n7XKpjRmDkHENymaBw7rU71wxQnrW4i6DDrQP",
"products": [
"investments",
"liabilities",
"transactions"
],
"update_type": "background",
"webhook": ""
},
"liabilities": {
"credit": [
{
"account_id": "RperV9wJMNiDWKljGMkPCkwDGJb7q7FaNlVMp",
"aprs": [
{
"apr_percentage": 12.5,
"apr_type": "purchase_apr",
"balance_subject_to_apr": null,
"interest_charge_amount": null
},
{
"apr_percentage": 27.95,
"apr_type": "cash_apr",
"balance_subject_to_apr": null,
"interest_charge_amount": null
}
],
"is_overdue": false,
"last_payment_amount": null,
"last_payment_date": "2025-04-24",
"last_statement_balance": 1000,
"last_statement_issue_date": "2025-05-19",
"minimum_payment_amount": 50,
"next_payment_due_date": "2025-06-19"
}
],
"mortgage": null,
"student": [
{
"account_id": "6Gwzm7nJ6ZU4VbqEyKzZszyPQ8keRet8Q97k7",
"account_number": "3117529572",
"disbursement_dates": [
"2023-05-01"
],
"expected_payoff_date": "2036-05-01",
"guarantor": "DEPT OF ED",
"interest_rate_percentage": 5.25,
"is_overdue": false,
"last_payment_amount": null,
"last_payment_date": null,
"last_statement_balance": 16577.16,
"last_statement_issue_date": "2025-05-01",
"loan_name": "Consolidation",
"loan_status": {
"end_date": null,
"type": "in school"
},
"minimum_payment_amount": 25,
"next_payment_due_date": "2025-06-01",
"origination_date": "2023-05-01",
"origination_principal_amount": 15000,
"outstanding_interest_amount": 1577.16,
"payment_reference_number": "3117529572",
"pslf_status": {
"estimated_eligibility_date": null,
"payments_made": null,
"payments_remaining": null
},
"repayment_plan": {
"description": "Standard Repayment",
"type": "standard"
},
"sequence_number": "1",
"servicer_address": {
"city": "San Matias",
"country": "US",
"postal_code": "99415",
"region": "CA",
"street": "123 Relaxation Road"
},
"ytd_interest_paid": 0,
"ytd_principal_paid": 0
}
]
},
"request_id": "nFlL291sKIy1LkJ"
}
recorded_at: Mon, 19 May 2025 17:24:04 GMT
recorded_with: VCR 6.3.1

View file

@ -0,0 +1,64 @@
---
http_interactions:
- request:
method: post
uri: https://sandbox.plaid.com/link/token/create
body:
encoding: UTF-8
string: '{"client_name":"Maybe Finance","language":"en","country_codes":["US","CA"],"user":{"client_user_id":"test-user-id"},"products":["transactions"],"additional_consented_products":["investments","liabilities"],"webhook":"https://example.com/webhooks","redirect_uri":"http://localhost:3000/accounts","transactions":{"days_requested":730}}'
headers:
Content-Type:
- application/json
User-Agent:
- Plaid Ruby v38.0.0
Accept:
- application/json
Plaid-Client-Id:
- "<PLAID_CLIENT_ID>"
Plaid-Version:
- '2020-09-14'
Plaid-Secret:
- "<PLAID_SECRET>"
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 19 May 2025 17:24:04 GMT
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '146'
Connection:
- keep-alive
Plaid-Version:
- '2020-09-14'
Vary:
- Accept-Encoding
X-Envoy-Upstream-Service-Time:
- '70'
X-Envoy-Decorator-Operation:
- default.svc-apiv2:8080/*
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
X-Xss-Protection:
- 1; mode=block
body:
encoding: ASCII-8BIT
string: |-
{
"expiration": "2025-05-19T21:24:04Z",
"link_token": "link-sandbox-33432e02-32e2-415d-8f00-e626c6f4c6a6",
"request_id": "Gys5pGY7tIPDrlL"
}
recorded_at: Mon, 19 May 2025 17:24:04 GMT
recorded_with: VCR 6.3.1