Synth tests

This commit is contained in:
Zach Gollwitzer
2025-03-15 18:31:36 -04:00
parent 1a60fd4709
commit aa78942836
16 changed files with 882 additions and 102 deletions

View File

@@ -5,11 +5,11 @@ module ExchangeRate::Provideable
FetchRateData = Data.define(:rate)
FetchRatesData = Data.define(:rates)
def fetch_rate(from:, to:, date:)
raise NotImplementedError, "Subclasses must implement #fetch_rate"
def fetch_exchange_rate(from:, to:, date:)
raise NotImplementedError, "Subclasses must implement #fetch_exchange_rate"
end
def fetch_rates(from:, to:, start_date:, end_date:)
raise NotImplementedError, "Subclasses must implement #fetch_rates"
def fetch_exchange_rates(from:, to:, start_date:, end_date:)
raise NotImplementedError, "Subclasses must implement #fetch_exchange_rates"
end
end

View File

@@ -2,6 +2,7 @@ class Provider
include Retryable
ProviderError = Class.new(StandardError)
ProviderResponse = Data.define(:success?, :data, :error)
def healthy?
raise NotImplementedError, "Subclasses must implement #healthy?"
@@ -16,11 +17,7 @@ class Provider
end
private
# Generic response formats
Response = Data.define(:success?, :data, :error)
PaginatedData = Data.define(:paginated, :first_page, :total_pages)
# Specific data payload formats
UsageData = Data.define(:used, :limit, :utilization, :plan)
# Subclasses can specify errors that can be retried
@@ -35,13 +32,13 @@ class Provider
yield
end
Response.new(
ProviderResponse.new(
success?: true,
data: data,
error: nil,
)
rescue StandardError => error
Response.new(
ProviderResponse.new(
success?: false,
data: nil,
error: error,

View File

@@ -54,7 +54,7 @@ class Provider::Synth < Provider
exchange_mic = data.first_page.dig("exchange", "mic_code")
exchange_operating_mic = data.first_page.dig("exchange", "operating_mic_code")
Security::Price::Provideable::PricesData.new(
Security::Provideable::PricesData.new(
prices: data.paginated.map do |price|
Security::Price.new(
security: Security.new(

View File

@@ -3,20 +3,34 @@ require "test_helper"
module ExchangeRateProviderInterfaceTest
extend ActiveSupport::Testing::Declarative
test "exchange rate provider interface" do
assert_respond_to @subject, :healthy?
assert_respond_to @subject, :fetch_exchange_rate
assert_respond_to @subject, :fetch_exchange_rates
end
test "fetches single exchange rate" do
VCR.use_cassette("#{vcr_key_prefix}/exchange_rate") do
response = @subject.fetch_exchange_rate(
from: "USD",
to: "GBP",
date: Date.parse("01.01.2024")
)
test "exchange rate provider response contract" do
VCR.use_cassette "synth/exchange_rate" do
response = @subject.fetch_exchange_rate from: "USD", to: "MXN", date: Date.iso8601("2024-08-01")
rate = response.data.rate
assert_respond_to response, :rate
assert_respond_to response, :success?
assert_respond_to response, :error
assert_respond_to response, :raw_response
assert_kind_of ExchangeRate, rate
assert_equal "USD", rate.from_currency
assert_equal "GBP", rate.to_currency
end
end
test "fetches paginated exchange_rate historical data" do
VCR.use_cassette("#{vcr_key_prefix}/exchange_rates") do
response = @subject.fetch_exchange_rates(
from: "USD", to: "GBP", start_date: Date.parse("01.01.2024"), end_date: Date.parse("31.07.2024")
)
assert 213, response.data.rates.count # 213 days between 01.01.2024 and 31.07.2024
end
end
private
def vcr_key_prefix
@subject.class.name.demodulize.underscore
end
end

View File

@@ -1,26 +0,0 @@
require "test_helper"
module SecurityPriceProviderInterfaceTest
extend ActiveSupport::Testing::Declarative
test "security price provider interface" do
assert_respond_to @subject, :healthy?
assert_respond_to @subject, :fetch_security_prices
end
test "security price provider response contract" do
VCR.use_cassette "synth/security_prices" do
response = @subject.fetch_security_prices(
ticker: "AAPL",
mic_code: "XNAS",
start_date: Date.iso8601("2024-01-01"),
end_date: Date.iso8601("2024-08-01")
)
assert_respond_to response, :prices
assert_respond_to response, :success?
assert_respond_to response, :error
assert_respond_to response, :raw_response
end
end
end

View File

@@ -0,0 +1,48 @@
require "test_helper"
module SecurityProviderInterfaceTest
extend ActiveSupport::Testing::Declarative
test "fetches paginated securities prices" do
VCR.use_cassette("#{vcr_key_prefix}/security_prices") do
response = @subject.fetch_security_prices(
ticker: "AAPL",
operating_mic_code: "XNAS",
start_date: Date.iso8601("2024-01-01"),
end_date: Date.iso8601("2024-08-01")
)
assert 213, response.data.prices.count
end
end
test "searches securities" do
VCR.use_cassette("#{vcr_key_prefix}/security_search") do
response = @subject.search_securities("AAPL", country_code: "US")
securities = response.data.securities
assert securities.any?
security = securities.first
assert_kind_of Security, security
assert_equal "AAPL", security.ticker
end
end
test "fetches security info" do
VCR.use_cassette("#{vcr_key_prefix}/security_info") do
response = @subject.fetch_security_info(ticker: "AAPL", operating_mic: "XNAS")
info = response.data
assert_equal "AAPL", info.ticker
assert_equal "Apple Inc.", info.name
assert info.logo_url.present?
assert_equal "common stock", info.kind
assert info.description.present?
end
end
private
def vcr_key_prefix
@subject.class.name.demodulize.underscore
end
end

View File

@@ -2,57 +2,43 @@ require "test_helper"
require "ostruct"
class Provider::SynthTest < ActiveSupport::TestCase
include ExchangeRateProviderInterfaceTest, SecurityPriceProviderInterfaceTest
include ExchangeRateProviderInterfaceTest, SecurityProviderInterfaceTest
setup do
@subject = @synth = Provider::Synth.new(ENV["SYNTH_API_KEY"])
end
test "fetches paginated securities prices" do
VCR.use_cassette("synth/security_prices") do
response = @synth.fetch_security_prices(
ticker: "AAPL",
mic_code: "XNAS",
start_date: Date.iso8601("2024-01-01"),
end_date: Date.iso8601("2024-08-01")
)
puts response
assert 213, response
test "health check" do
VCR.use_cassette("synth/health") do
assert @synth.healthy?
end
end
test "fetches paginated exchange_rate historical data" do
VCR.use_cassette("synth/exchange_rate_historical") do
response = @synth.fetch_exchange_rates(
from: "USD", to: "GBP", start_date: Date.parse("01.01.2024"), end_date: Date.parse("31.07.2024")
)
assert 213, response.rates.size # 213 days between 01.01.2024 and 31.07.2024
assert_equal [ :date, :rate ], response.rates.first.keys
test "usage info" do
VCR.use_cassette("synth/usage") do
usage = @synth.usage.data
assert usage.used.present?
assert usage.limit.present?
assert usage.utilization.present?
assert usage.plan.present?
end
end
test "retries then provides failed response" do
@client = mock
Faraday.stubs(:new).returns(@client)
test "enriches transaction" do
VCR.use_cassette("synth/transaction_enrich") do
response = @synth.enrich_transaction(
"UBER EATS",
amount: 25.50,
date: Date.today,
city: "San Francisco",
state: "CA",
country: "US"
)
@client.expects(:get).returns(OpenStruct.new(success?: false)).times(3)
data = response.data
response = @synth.fetch_exchange_rate from: "USD", to: "MXN", date: Date.iso8601("2024-08-01")
assert_match "Failed to fetch data from Provider::Synth", response.error.message
end
test "retrying, then raising on network error" do
@client = mock
Faraday.stubs(:new).returns(@client)
@client.expects(:get).raises(Faraday::TimeoutError).times(3)
assert_raises Faraday::TimeoutError do
@synth.fetch_exchange_rate from: "USD", to: "MXN", date: Date.iso8601("2024-08-01")
assert data.name.present?
assert data.category.present?
end
end
end

View File

@@ -0,0 +1,61 @@
require "test_helper"
require "ostruct"
class TestProvider < Provider
def fetch_data
provider_response(retries: 3) do
client.get("/test")
end
end
private
def client
@client ||= Faraday.new
end
def retryable_errors
[ Faraday::TimeoutError ]
end
end
class ProviderTest < ActiveSupport::TestCase
setup do
@provider = TestProvider.new
end
test "retries then provides failed response" do
client = mock
Faraday.stubs(:new).returns(client)
client.expects(:get)
.with("/test")
.raises(Faraday::TimeoutError)
.times(3)
response = @provider.fetch_data
assert_not response.success?
assert_match "timeout", response.error.message
end
test "fail, retry, succeed" do
client = mock
Faraday.stubs(:new).returns(client)
sequence = sequence("retry_sequence")
client.expects(:get)
.with("/test")
.raises(Faraday::TimeoutError)
.in_sequence(sequence)
client.expects(:get)
.with("/test")
.returns(Provider::ProviderResponse.new(success?: true, data: "success", error: nil))
.in_sequence(sequence)
response = @provider.fetch_data
assert response.success?
end
end

View File

@@ -0,0 +1,81 @@
---
http_interactions:
- request:
method: get
uri: https://api.synthfinance.com/rates/historical?date=2024-01-01&from=USD&to=GBP
body:
encoding: US-ASCII
string: ''
headers:
Authorization:
- Bearer <SYNTH_API_KEY>
X-Source:
- maybe_app
X-Source-Type:
- managed
User-Agent:
- Faraday v2.12.2
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept:
- "*/*"
response:
status:
code: 200
message: OK
headers:
Date:
- Sat, 15 Mar 2025 22:18:46 GMT
Content-Type:
- application/json; charset=utf-8
Transfer-Encoding:
- chunked
Connection:
- keep-alive
Cache-Control:
- max-age=0, private, must-revalidate
Etag:
- W/"b0b21c870fe53492404cc5ac258fa465"
Referrer-Policy:
- strict-origin-when-cross-origin
Rndr-Id:
- 44367fcb-e5b4-457d
Strict-Transport-Security:
- max-age=63072000; includeSubDomains
Vary:
- Accept-Encoding
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- SAMEORIGIN
X-Permitted-Cross-Domain-Policies:
- none
X-Render-Origin-Server:
- Render
X-Request-Id:
- 8ce9dc85-afbd-437c-b18d-ec788b712334
X-Runtime:
- '0.031963'
X-Xss-Protection:
- '0'
Cf-Cache-Status:
- DYNAMIC
Report-To:
- '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=SwRPS1vBsrKtk%2Ftb7Ix8j%2FCWYw9tZgbJxR1FCmotWn%2FIZAE3Ri%2FUwHtvkOSqBq6HN5pLVetfem5hp%2BkqWmD5GRCVho0mp3VgRr3J1tBMwrVK2p50tfpmb3X22Jj%2BOfapq1C22PnN"}],"group":"cf-nel","max_age":604800}'
Nel:
- '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}'
Speculation-Rules:
- '"/cdn-cgi/speculation"'
Server:
- cloudflare
Cf-Ray:
- 920f6378fe582237-ORD
Alt-Svc:
- h3=":443"; ma=86400
Server-Timing:
- cfL4;desc="?proto=TCP&rtt=26670&min_rtt=26569&rtt_var=10167&sent=4&recv=6&lost=0&retrans=0&sent_bytes=2829&recv_bytes=922&delivery_rate=105759&cwnd=181&unsent_bytes=0&cid=f0a872e0b2909c59&ts=188&x=0"
body:
encoding: ASCII-8BIT
string: '{"data":{"date":"2024-01-01","source":"USD","rates":{"GBP":0.785476}},"meta":{"total_records":1,"credits_used":1,"credits_remaining":249830,"date":"2024-01-01"}}'
recorded_at: Sat, 15 Mar 2025 22:18:46 GMT
recorded_with: VCR 6.3.1

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,82 @@
---
http_interactions:
- request:
method: get
uri: https://api.synthfinance.com/user
body:
encoding: US-ASCII
string: ''
headers:
Authorization:
- Bearer <SYNTH_API_KEY>
X-Source:
- maybe_app
X-Source-Type:
- managed
User-Agent:
- Faraday v2.12.2
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept:
- "*/*"
response:
status:
code: 200
message: OK
headers:
Date:
- Sat, 15 Mar 2025 22:18:47 GMT
Content-Type:
- application/json; charset=utf-8
Transfer-Encoding:
- chunked
Connection:
- keep-alive
Cache-Control:
- max-age=0, private, must-revalidate
Etag:
- W/"4ec3e0a20895d90b1e1241ca67f10ca3"
Referrer-Policy:
- strict-origin-when-cross-origin
Rndr-Id:
- 0cab64c9-e312-4bec
Strict-Transport-Security:
- max-age=63072000; includeSubDomains
Vary:
- Accept-Encoding
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- SAMEORIGIN
X-Permitted-Cross-Domain-Policies:
- none
X-Render-Origin-Server:
- Render
X-Request-Id:
- 1958563c-7c18-4201-a03c-a4b343dc68ab
X-Runtime:
- '0.014938'
X-Xss-Protection:
- '0'
Cf-Cache-Status:
- DYNAMIC
Report-To:
- '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=P3OWn4c8LFFWI0Dwr2CSYwHLaNhf9iD9TfAhqdx5PtLoWZ0pSImebfUsh00ZbOmh4r2cRJEQOmvy67wAwl6p0W%2Fx9017EkCnCaXibBBCKqJTBOdGnsSuV%2B45LrHsQmg%2BGeBwrw4b"}],"group":"cf-nel","max_age":604800}'
Nel:
- '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}'
Speculation-Rules:
- '"/cdn-cgi/speculation"'
Server:
- cloudflare
Cf-Ray:
- 920f637aa8cf1152-ORD
Alt-Svc:
- h3=":443"; ma=86400
Server-Timing:
- cfL4;desc="?proto=TCP&rtt=25627&min_rtt=25594&rtt_var=9664&sent=4&recv=6&lost=0&retrans=0&sent_bytes=2827&recv_bytes=878&delivery_rate=111991&cwnd=248&unsent_bytes=0&cid=c8e4c4e269114d14&ts=263&x=0"
body:
encoding: ASCII-8BIT
string: '{"id":"user_3208c49393f54b3e974795e4bea5b864","email":"test@maybe.co","name":"Test
User","plan":"Business","api_calls_remaining":249830,"api_limit":250000,"credits_reset_at":"2025-04-01T00:00:00.000-04:00","current_period_start":"2025-03-01T00:00:00.000-05:00"}'
recorded_at: Sat, 15 Mar 2025 22:18:47 GMT
recorded_with: VCR 6.3.1

View File

@@ -0,0 +1,105 @@
---
http_interactions:
- request:
method: get
uri: https://api.synthfinance.com/tickers/AAPL?operating_mic=XNAS
body:
encoding: US-ASCII
string: ''
headers:
Authorization:
- Bearer <SYNTH_API_KEY>
X-Source:
- maybe_app
X-Source-Type:
- managed
User-Agent:
- Faraday v2.12.2
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept:
- "*/*"
response:
status:
code: 200
message: OK
headers:
Date:
- Sat, 15 Mar 2025 22:18:44 GMT
Content-Type:
- application/json; charset=utf-8
Transfer-Encoding:
- chunked
Connection:
- keep-alive
Cache-Control:
- max-age=0, private, must-revalidate
Etag:
- W/"d85a3324210bb92817e22bb889e82e6b"
Referrer-Policy:
- strict-origin-when-cross-origin
Rndr-Id:
- 2ecd0f12-8986-4176
Strict-Transport-Security:
- max-age=63072000; includeSubDomains
Vary:
- Accept-Encoding
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- SAMEORIGIN
X-Permitted-Cross-Domain-Policies:
- none
X-Render-Origin-Server:
- Render
X-Request-Id:
- ae77d8b5-8580-46ee-ab44-1617e2a99cbe
X-Runtime:
- '0.033125'
X-Xss-Protection:
- '0'
Cf-Cache-Status:
- DYNAMIC
Report-To:
- '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=kWMI2ehyl3ZVgLwNHnKsggdrcOj%2B%2FrRUSzRX0QUx03%2Bgiupmbnfwv2NVlp0LOQ8qT4mWB6Sl5lOOaj3lnkegAmAhN4swD%2B2e0FbgK19Du7LoXBBRKokMwh84wsfuB6xWT3XtOxli"}],"group":"cf-nel","max_age":604800}'
Nel:
- '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}'
Speculation-Rules:
- '"/cdn-cgi/speculation"'
Server:
- cloudflare
Cf-Ray:
- 920f636c7e571236-ORD
Alt-Svc:
- h3=":443"; ma=86400
Server-Timing:
- cfL4;desc="?proto=TCP&rtt=31470&min_rtt=30733&rtt_var=12999&sent=5&recv=6&lost=0&retrans=0&sent_bytes=2828&recv_bytes=905&delivery_rate=79056&cwnd=202&unsent_bytes=0&cid=9696d1468ed35efd&ts=312&x=0"
body:
encoding: ASCII-8BIT
string: '{"data":{"ticker":"AAPL","name":"Apple Inc.","links":{"homepage_url":"https://www.apple.com"},"logo_url":"https://logo.synthfinance.com/ticker/AAPL","description":"Apple
Inc. designs, manufactures, and markets smartphones, personal computers, tablets,
wearables, and accessories worldwide. The company offers iPhone, a line of
smartphones; Mac, a line of personal computers; iPad, a line of multi-purpose
tablets; and wearables, home, and accessories comprising AirPods, Apple TV,
Apple Watch, Beats products, and HomePod. It also provides AppleCare support
and cloud services; and operates various platforms, including the App Store
that allow customers to discover and download applications and digital content,
such as books, music, video, games, and podcasts. In addition, the company
offers various services, such as Apple Arcade, a game subscription service;
Apple Fitness+, a personalized fitness service; Apple Music, which offers
users a curated listening experience with on-demand radio stations; Apple
News+, a subscription news and magazine service; Apple TV+, which offers exclusive
original content; Apple Card, a co-branded credit card; and Apple Pay, a cashless
payment service, as well as licenses its intellectual property. The company
serves consumers, and small and mid-sized businesses; and the education, enterprise,
and government markets. It distributes third-party applications for its products
through the App Store. The company also sells its products through its retail
and online stores, and direct sales force; and third-party cellular network
carriers, wholesalers, retailers, and resellers. Apple Inc. was founded in
1976 and is headquartered in Cupertino, California.","kind":"common stock","cik":"0000320193","currency":"USD","address":{"country":"USA","address_line1":"One
Apple Park Way","city":"Cupertino","state":"CA","postal_code":"95014"},"exchange":{"name":"Nasdaq/Ngs
(Global Select Market)","mic_code":"XNGS","operating_mic_code":"XNAS","acronym":"NGS","country":"United
States","country_code":"US","timezone":"America/New_York"},"ceo":"Mr. Timothy
D. Cook","founding_year":1976,"industry":"Consumer Electronics","sector":"Technology","phone":"408-996-1010","total_employees":161000,"composite_figi":"BBG000B9Y5X2","market_data":{"high_today":213.95,"low_today":209.58,"open_today":211.25,"close_today":213.49,"volume_today":60060200.0,"fifty_two_week_high":260.1,"fifty_two_week_low":164.08,"average_volume":62654621.76119403,"price_change":0.0,"percent_change":0.0}},"meta":{"credits_used":1,"credits_remaining":249831}}'
recorded_at: Sat, 15 Mar 2025 22:18:44 GMT
recorded_with: VCR 6.3.1

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,104 @@
---
http_interactions:
- request:
method: get
uri: https://api.synthfinance.com/tickers/search?country_code=US&dataset=limited&limit=25&name=AAPL
body:
encoding: US-ASCII
string: ''
headers:
Authorization:
- Bearer <SYNTH_API_KEY>
X-Source:
- maybe_app
X-Source-Type:
- managed
User-Agent:
- Faraday v2.12.2
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept:
- "*/*"
response:
status:
code: 200
message: OK
headers:
Date:
- Sat, 15 Mar 2025 22:18:47 GMT
Content-Type:
- application/json; charset=utf-8
Transfer-Encoding:
- chunked
Connection:
- keep-alive
Cache-Control:
- max-age=0, private, must-revalidate
Etag:
- W/"3e444869eacbaf17006766a691cc8fdc"
Referrer-Policy:
- strict-origin-when-cross-origin
Rndr-Id:
- 83bf5921-953a-412a
Strict-Transport-Security:
- max-age=63072000; includeSubDomains
Vary:
- Accept-Encoding
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- SAMEORIGIN
X-Permitted-Cross-Domain-Policies:
- none
X-Render-Origin-Server:
- Render
X-Request-Id:
- b71386a8-ddc4-4f1b-9beb-70ce8420b825
X-Runtime:
- '0.028724'
X-Xss-Protection:
- '0'
Cf-Cache-Status:
- DYNAMIC
Report-To:
- '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=mdeHEBVe0gLU3kdkCvgGuUYjQ0Zc6QXQs%2FRuuNM9tgGyk5Yrgyb%2Bb4Rv0HbCh45Dg2LDRPIuRV63jztLR96oNBxiJZpJBRV1D0Lcbf%2Fge4NNE04GDo6TB0s98lpzjbjcwdkc1eEe"}],"group":"cf-nel","max_age":604800}'
Nel:
- '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}'
Speculation-Rules:
- '"/cdn-cgi/speculation"'
Server:
- cloudflare
Cf-Ray:
- 920f637e8869022c-ORD
Alt-Svc:
- h3=":443"; ma=86400
Server-Timing:
- cfL4;desc="?proto=TCP&rtt=27260&min_rtt=26674&rtt_var=11175&sent=4&recv=6&lost=0&retrans=0&sent_bytes=2829&recv_bytes=939&delivery_rate=92329&cwnd=179&unsent_bytes=0&cid=e32a34e1041ad30b&ts=296&x=0"
body:
encoding: ASCII-8BIT
string: '{"data":[{"symbol":"AAPL","name":"Apple Inc.","logo_url":"https://logo.synthfinance.com/ticker/AAPL","currency":"USD","exchange":{"name":"Nasdaq/Ngs
(Global Select Market)","mic_code":"XNGS","operating_mic_code":"XNAS","acronym":"NGS","country":"United
States","country_code":"US","timezone":"America/New_York"}},{"symbol":"APLY","isin":"US88634T8577","name":"YieldMax
AAPL Option Income ETF","logo_url":"https://logo.synthfinance.com/ticker/APLY","currency":"USD","exchange":{"name":"Nyse
Arca","mic_code":"ARCX","operating_mic_code":"XNYS","acronym":"NYSE","country":"United
States","country_code":"US","timezone":"America/New_York"}},{"symbol":"AAPD","name":"Direxion
Daily AAPL Bear 1X ETF","logo_url":"https://logo.synthfinance.com/ticker/AAPD","currency":"USD","exchange":{"name":"Nasdaq/Nms
(Global Market)","mic_code":"XNMS","operating_mic_code":"XNAS","acronym":"","country":"United
States","country_code":"US","timezone":"America/New_York"}},{"symbol":"AAPU","isin":"US25461A8743","name":"Direxion
Daily AAPL Bull 2X Shares","logo_url":"https://logo.synthfinance.com/ticker/AAPU","currency":"USD","exchange":{"name":"Nasdaq/Nms
(Global Market)","mic_code":"XNMS","operating_mic_code":"XNAS","acronym":"","country":"United
States","country_code":"US","timezone":"America/New_York"}},{"symbol":"AAPB","isin":"XXXXXXXR8842","name":"GraniteShares
2x Long AAPL Daily ETF","logo_url":"https://logo.synthfinance.com/ticker/AAPB","currency":"USD","exchange":{"name":"Nasdaq/Ngs
(Global Select Market)","mic_code":"XNGS","operating_mic_code":"XNAS","acronym":"NGS","country":"United
States","country_code":"US","timezone":"America/New_York"}},{"symbol":"AAPD","isin":"US25461A3041","name":"Direxion
Daily AAPL Bear 1X Shares","logo_url":"https://logo.synthfinance.com/ticker/AAPD","currency":"USD","exchange":{"name":"Nasdaq/Ngs
(Global Select Market)","mic_code":"XNGS","operating_mic_code":"XNAS","acronym":"NGS","country":"United
States","country_code":"US","timezone":"America/New_York"}},{"symbol":"AAPU","isin":"US25461A8743","name":"Direxion
Daily AAPL Bull 1.5X Shares","logo_url":"https://logo.synthfinance.com/ticker/AAPU","currency":"USD","exchange":{"name":"Nasdaq/Ngs
(Global Select Market)","mic_code":"XNGS","operating_mic_code":"XNAS","acronym":"NGS","country":"United
States","country_code":"US","timezone":"America/New_York"}},{"symbol":"AAPJ","isin":"US00037T1034","name":"AAP,
Inc.","logo_url":"https://logo.synthfinance.com/ticker/AAPJ","currency":"USD","exchange":{"name":"Otc
Pink Marketplace","mic_code":"PINX","operating_mic_code":"OTCM","acronym":"","country":"United
States","country_code":"US","timezone":"America/New_York"}}]}'
recorded_at: Sat, 15 Mar 2025 22:18:47 GMT
recorded_with: VCR 6.3.1

View File

@@ -0,0 +1,82 @@
---
http_interactions:
- request:
method: get
uri: https://api.synthfinance.com/enrich?amount=25.5&city=San%20Francisco&country=US&date=2025-03-15&description=UBER%20EATS&state=CA
body:
encoding: US-ASCII
string: ''
headers:
Authorization:
- Bearer <SYNTH_API_KEY>
X-Source:
- maybe_app
X-Source-Type:
- managed
User-Agent:
- Faraday v2.12.2
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept:
- "*/*"
response:
status:
code: 200
message: OK
headers:
Date:
- Sat, 15 Mar 2025 22:18:46 GMT
Content-Type:
- application/json; charset=utf-8
Transfer-Encoding:
- chunked
Connection:
- keep-alive
Cache-Control:
- max-age=0, private, must-revalidate
Etag:
- W/"1db909926620ba097a4a150be27740e4"
Referrer-Policy:
- strict-origin-when-cross-origin
Rndr-Id:
- 58ab5340-1bd7-4d53
Strict-Transport-Security:
- max-age=63072000; includeSubDomains
Vary:
- Accept-Encoding
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- SAMEORIGIN
X-Permitted-Cross-Domain-Policies:
- none
X-Render-Origin-Server:
- Render
X-Request-Id:
- '008d26b5-f9e2-4ea6-bf0b-30e02cafac01'
X-Runtime:
- '1.148648'
X-Xss-Protection:
- '0'
Cf-Cache-Status:
- DYNAMIC
Report-To:
- '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=Eq98WTRmuxpGKmjEufUY5yMHuojtlgeeOpORSOT42JAeV36tGCl6y3XGKJjz5ZZrA9t3yV6QNWiLR2bSUzWQh2GbHKgMT2Ze%2BCT4dnEApiOrqIw3FUCG3cC0AM%2FU%2BIYcq%2FuH30OJ"}],"group":"cf-nel","max_age":604800}'
Nel:
- '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}'
Speculation-Rules:
- '"/cdn-cgi/speculation"'
Server:
- cloudflare
Cf-Ray:
- 920f636f7e942a12-ORD
Alt-Svc:
- h3=":443"; ma=86400
Server-Timing:
- cfL4;desc="?proto=TCP&rtt=27114&min_rtt=26324&rtt_var=11453&sent=4&recv=6&lost=0&retrans=0&sent_bytes=2828&recv_bytes=969&delivery_rate=88695&cwnd=213&unsent_bytes=0&cid=20ad3ba4a51c6fd3&ts=1308&x=0"
body:
encoding: ASCII-8BIT
string: '{"merchant":"Uber Eats","merchant_id":"mer_aea41e7f29ce47b5873f3caf49d5972d","category":"Dining
Out","website":"ubereats.com","icon":"https://logo.synthfinance.com/ubereats.com","meta":{"credits_used":1,"credits_remaining":249830}}'
recorded_at: Sat, 15 Mar 2025 22:18:46 GMT
recorded_with: VCR 6.3.1

View File

@@ -0,0 +1,82 @@
---
http_interactions:
- request:
method: get
uri: https://api.synthfinance.com/user
body:
encoding: US-ASCII
string: ''
headers:
Authorization:
- Bearer <SYNTH_API_KEY>
X-Source:
- maybe_app
X-Source-Type:
- managed
User-Agent:
- Faraday v2.12.2
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept:
- "*/*"
response:
status:
code: 200
message: OK
headers:
Date:
- Sat, 15 Mar 2025 22:18:47 GMT
Content-Type:
- application/json; charset=utf-8
Transfer-Encoding:
- chunked
Connection:
- keep-alive
Cache-Control:
- max-age=0, private, must-revalidate
Etag:
- W/"4ec3e0a20895d90b1e1241ca67f10ca3"
Referrer-Policy:
- strict-origin-when-cross-origin
Rndr-Id:
- 54c8ecf9-6858-4db6
Strict-Transport-Security:
- max-age=63072000; includeSubDomains
Vary:
- Accept-Encoding
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- SAMEORIGIN
X-Permitted-Cross-Domain-Policies:
- none
X-Render-Origin-Server:
- Render
X-Request-Id:
- a4112cfb-0eac-4e3e-a880-7536d90dcba0
X-Runtime:
- '0.007036'
X-Xss-Protection:
- '0'
Cf-Cache-Status:
- DYNAMIC
Report-To:
- '{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=Rt0BTtrgXzYjWOQFgb%2Bg6N4xKvXtPI66Q251bq9nWtqUhGHo17GmVVAPkutwN7Gisw1RmvYfxYUiMCCxlc4%2BjuHxbU1%2BXr9KHy%2F5pUpLhgLNNrtkqqKOCW4GduODnDbw2I38Rocu"}],"group":"cf-nel","max_age":604800}'
Nel:
- '{"success_fraction":0,"report_to":"cf-nel","max_age":604800}'
Speculation-Rules:
- '"/cdn-cgi/speculation"'
Server:
- cloudflare
Cf-Ray:
- 920f637d1fe8eb68-ORD
Alt-Svc:
- h3=":443"; ma=86400
Server-Timing:
- cfL4;desc="?proto=TCP&rtt=28779&min_rtt=27036&rtt_var=11384&sent=5&recv=6&lost=0&retrans=0&sent_bytes=2828&recv_bytes=878&delivery_rate=107116&cwnd=203&unsent_bytes=0&cid=52bc39ad09dd9eff&ts=145&x=0"
body:
encoding: ASCII-8BIT
string: '{"id":"user_3208c49393f54b3e974795e4bea5b864","email":"test@maybe.co","name":"Test
User","plan":"Business","api_calls_remaining":1200,"api_limit":5000,"credits_reset_at":"2025-04-01T00:00:00.000-04:00","current_period_start":"2025-03-01T00:00:00.000-05:00"}'
recorded_at: Sat, 15 Mar 2025 22:18:47 GMT
recorded_with: VCR 6.3.1