Mystic Morpho REST API
Read real-time Morpho data on the chains Mystic is on, including vaults and markets data, APYs, TVL, liquidity, rewards and much more.
Introduction
The Mystic Morpho API lets you read all kinds of Morpho data in real-time on the chains Morpho is on. Track your positions, liquidate, manage risk or build your own Morpho-powered app using Mystic's Morpho API. Note that to use it, you will need your own API Key. Please contact us to get an API Key and get started -> Contact us.
Base URL
https://api.mysticfinance.xyzhttps://staging-api.mysticfinance.xyzOpenAPI Specification
The full machine-readable API spec available for AI agents, code generators, and API clients:
Swagger UI
OpenAPI JSON
Contents
Why Mystic
Authentication
Quickstart
API reference
General
Vaults
Borrows
Portfolio
Transactions
Historical
Realtime
Liquidations
Supported protocols and chains
Errors
Why Mystic
Use one API for DeFi earn and borrow data, risk context, eligibility screening, portfolio tracking, position history, and live on-chain state.
Mystic is the API layer for onchain earn and borrow features. Use one integration to discover vaults, compare risk and return, screen out markets that should never reach a user, size a borrow, track positions and returns after a deposit, and see what happened when capital move across 1.5K+ vaults, 5.5k+ borrow markets, and 6+ chains.
Use Mystic when your product needs to do more than show APYs, to decide which vaults and markets are eligible, explain why one beats another, tell a user what they hold and what it has earned, and report what happened after capital moved, including the liquidations.
Authentication
To call the API, you need to an API Key. Contact the Mystic team to get one and add it to the header of the api call like below. API Key usage is billed monthly and the Key will expire if payment fails. An expired key returns 401.
Rate limit: 20 - 100 requests/second on data endpoints depending on your API plan. When you are over the limit, it returns 429
Contact us to get your API Key
Quickstart
Read a vault and a user's position in it, in 5 steps:
Fetch the list of vaults
Fetch a vault's details
Fetch a vault's allocations
Check a user's position in that vault
Check the whole portfolio
Read a borrow market and a user's position in it, in 6 steps:
Fetch the list of borrow markets
Fetch a market's details
Fetch a market's allocations
Check a user's borrow positions
Narrow to one market
Check the whole portfolio
Two conventions before you start:
Rates are decimal fractions, not percentages. 0.0752 means 7.52%. This holds for every APY, LLTV, utilization, fee and liquidation penalty in every request and response, minApy=0.05 filters at 5%, not 5 basis points.
Amounts are decimal strings, not numbers. "12403118.44", already scaled by the token's decimals.
All examples use JavaScript with axios for HTTP.
Vaults
1. Fetch the list of vaults
Filter and rank across every supported network in one call. This is the endpoint a "where should I deposit?" screen is built on:
Example response (GET /vaults?assetGroup=usd&minTvl=1000000&minApy=0.05&sortBy=apy&perPage=10):
Read apy.instantaneous.reward against apy["30day"].reward before you render a headline rate.
2. Fetch a vault's details
Split the vaultId and read the vault in full:
The detail response is the same object as the list plus allocations, governance, collaterals, capacity, protocolSpecific and the full score breakdown, see the vault object for every field.
A missing vault is a 404, never a 200 with a null body, so a failed lookup throws 404 in axios.
3. Fetch a vault's allocations
Where the deposits actually go, the answer to "what risk am I taking?":
Example response, largest share first:
4. Check a user's position in that vault
Example response:
5. Check the whole portfolio
One call for every total across every indexed network:
Example response (GET /portfolio/summary/0xd8dA…6045):
Putting the vault flow together
Borrows
1. Fetch the list of borrow markets
Example response:
Bad-debt and unverified markets are excluded by default. Pass includeBadDebt=true / includeUnverified=true for the unfiltered set; both are also reported in tags and flags when present.
supplyingVaults is omitted from list rows to keep them small. Add ?expand=supplyingVaults when you need it in a list, an unrecognised expand value is a 400, not a silently slim response.
2. Fetch a market's details
The detail response adds reallocatableLiquidity, capacity, oracle, irm, fee, performanceFee, vaultCaps and the fully-expanded supplyingVaults, see the market object.
liquidity is everything reachable; reallocatableLiquidity is the slice that only arrives if a public allocator acts. Borrowing against the first number and assuming the second is instant is how a large draw fails at signing time.
3. Fetch a market's allocations
Which vaults back the market, and how much each has in it, depth is only as real as the vaults supplying it:
4. Check a user's borrow positions
Example response:
healthFactor is collateral × liquidation threshold ÷ debt, and is null when there is no debt, a position that cannot be liquidated has no health factor. Do not treat null as zero: it is the safest possible state, not the most dangerous one.
5. Narrow to one market
There is no per-market position route, borrow positions come back for the whole wallet, so filter the response by marketId:
Scope the fan-out with allowedNetworks when you already know the chain — it is one indexer round-trip per network, so naming the one you need is faster and no more expensive:
To see how a position got where it is, every borrow, repayment and liquidation against it — read /portfolio/events/{address} with eventType=borrow,repay,liquidation.
6. Check the whole portfolio
The same two calls as the vault flow. For a borrower, three fields carry the answer:
lowestHealthFactor is what an alerting system should watch. It is null only when the wallet has no debt anywhere.
Putting the borrow flow together
API reference
Every route below is prefixed with https://api.mysticfinance.xyz/v1/yields and all are GET endpoints.
The list envelope
Every list response, without exception:
errors is a degradation, not a failure. Ask for allowedNetworks=plume,atlantis and you get every Plume vault plus unsupportedNetworks: ["atlantis"] , rather than a 400 that discards the results you could have had.
Shared query parameters
Every list endpoint accepts these. Endpoint sections document only what they add.
page
integer
–
Default 1.
perPage
integer
–
Default 50, max 500.
allowedNetworks
string
–
Slugs or chain ids: plume,base or 98866,8453. Unknown entries land in errors.unsupportedNetworks.
disallowedNetworks
string
–
Same format, excluded instead.
chainId
integer
–
Single-network alias for callers migrating from /morphoCache.
search
string
–
Free-text match on name, symbol or address.
sortOrder
enum
–
asc | desc. Default desc.
/v1 is required on every route below.
General
/health
0
Per-network cache age
/networks
0
Supported networks with vault/market counts
/protocols
0
Protocols and their declared capabilities
/tags
0
Tag vocabulary with live counts
/curators
2
Curators with vault counts and TVL
/assets
2
Every asset used by a vault or market
/assets/{network}/{address}
2
One asset, with where it is used
GET /v1/yields/health
Freshness per chain, so you can decide what staleness you tolerate rather than trusting a bare 200. Exempt from rate limiting.
Request — no parameters.
Response
null for an age means that cache has never been written for that chain.
GET /v1/yields/networks
Request — no parameters.
Response
A supported network with zero counts is a real state (a chain whose cron has not populated yet), reported rather than hidden.
GET /v1/yields/protocols
Capabilities are advertised, not implied — you can see that a protocol cannot answer share-price history instead of discovering it as an empty series.
Request: no parameters.
Response
GET /v1/yields/tags
Counts come from the same derivation the vault list uses, so ?tags=stablecoin returns the number shown here.
Response
Full vocabulary: stablecoin, eth, btc, rwa, v2, incentivised, blue-chip, bad-debt, unverified.
GET /v1/yields/curators
Request — shared parameters only.
Response — list envelope, highest TVL first.
Curators named Unknown are omitted rather than aggregated into a fake entity.
GET /v1/yields/assets
Every asset that appears in a vault or market we index — derived, not curated. An asset outside that set has nowhere to be deposited, so listing it would be noise.
Request
assetGroup
csv
–
usd | eth | btc | rwa | other
Plus the shared parameters.
Response — list envelope, most-used first.
The same symbol on two chains is two entries, different tokens, different prices.
GET /v1/yields/assets/{network}/{address}
Request
network
path
✅
Network slug.
address
path
✅
Asset contract address.
Response: one asset object as above. 404 when the asset is not used by anything we index.
Vaults
/vaults
1
List vaults — the main discovery endpoint
/vaults/{network}/{vaultId}
1
One vault, in full
/vaults/{network}/{vaultId}/apy
1
APY breakdown alone — a cheap poll
/vaults/{network}/{vaultId}/tvl
1
TVL and liquidity alone
/vaults/{network}/{vaultId}/allocations
1
Where the vault deploys its assets
/vaults/{network}/{vaultId}/campaigns
2
Reward campaigns: token, budget, end date
/vaults/{network}/{vaultId}/holders
2
Holder count and largest positions
GET /v1/yields/vaults
Defaults to all networks, an omitted network filter is not silently treated as Plume.
Request
sortBy
enum
–
tvl (default), apy, liquidity, name, score, createdAt, holders
view
enum
–
full (default) | slim — see below
expand
string
–
score. Adds the component breakdown a list otherwise omits. An unrecognised value is a 400.
allowedAssets / disallowedAssets
string
–
Vault assets, by symbol or address
assetGroup
string
–
usd | eth | btc | rwa | other
allowedProtocols / disallowedProtocols
string
–
See /protocols
curators
string
–
Names or addresses
tags
string
–
See /tags
minTvl / maxTvl
number
–
USD
minApy / maxApy
number
–
Fractions. 0.05 is 5%.
apyInterval
enum
–
instantaneous, 1hour, 1day (default), 7day, 30day — which window minApy/maxApy/sortBy=apy read
minLiquidity
number
–
USD
minVaultScore
number
–
0–100. Vaults with no computed score are excluded — an unscored vault cannot satisfy a floor.
version
enum
–
v1 | v2 | all (default)
Plus the shared parameters.
Response: list envelope of vault objects.
view=slim returns identity, asset, APY, TVL and tags only — same vaults, same order, same filters, smaller payload:
It is a parameter rather than a second route so filtering and sorting cannot diverge between the two.
GET /v1/yields/vaults/{network}/{vaultId}
Request
network
path
✅
Network slug, e.g. plume.
vaultId
path
✅
Vault contract address.
Response — one vault object, including the detail-only fields. 404 when it does not exist.
The vault object
instantaneous is the spot rate,a null APY window is meaningful. It means no data covers that period, a two-day-old vault genuinely has no 30-day APY. The spot rate is never copied in.
Three allocation kinds exists, the first is the idle for idle liquidity, the second is market for market allocation and the third is vault for vault allocation. The vault allocation is only available for v2 vaults.
GET /v1/yields/vaults/{network}/{vaultId}/apy
GET /v1/yields/vaults/{network}/{vaultId}/tvl
GET /v1/yields/vaults/{network}/{vaultId}/allocations
Largest share first. The same array the detail response carries inline.
GET /v1/yields/vaults/{network}/{vaultId}/campaigns
Response
GET /v1/yields/vaults/{network}/{vaultId}/holders
Requires an indexer. See coverage.
Request — page, perPage (default 50, max 500).
Response
On an unindexed network the list is empty, totalCount is null, the network is in errors.unsupportedNetworks, and unavailableReason says why — rather than an empty array that reads as "this vault has no holders".
Borrows
/borrow/markets
1
List markets
/borrow/markets/{network}/{marketId}
1
One market
/borrow/markets/{network}/{marketId}/allocations
1
Which vaults supply it, and how much
GET /v1/yields/borrow/markets
Request
sortBy
enum
–
tvl (default), supplyApy, borrowApy, utilization, liquidity, lltv, score
expand
string
–
supplyingVaults, score. Unrecognised values are a 400.
allowedCollateralAssets / disallowedCollateralAssets
string
–
Symbol or address
allowedBorrowAssets / disallowedBorrowAssets
string
–
The loan asset, by symbol or address
allowedProtocols / disallowedProtocols
string
–
See /protocols
tags
string
–
See /tags
minTvl / maxTvl
number
–
Total supplied, USD
minLltv / maxLltv
number
–
Fractions. 0.86 is 86%.
minUtilization / maxUtilization
number
–
Fractions
minBorrowApy / maxBorrowApy
number
–
Fractions
minMarketScore
number
–
0–100
hasLiquidity
boolean
–
Only markets with borrowable liquidity
includeBadDebt
boolean
–
Default false
includeUnverified
boolean
–
Default false
Plus the shared parameters.
Response: list envelope of market objects.
GET /v1/yields/borrow/markets/{network}/{marketId}
Request
network
path
✅
Network slug.
marketId
path
✅
The 32-byte market id (without the network prefix).
The market object
liquidity vs reallocatableLiquidity. The first is total reachable liquidity: the market's own free liquidity plus whatever a public allocator can move in. The second is that reallocatable component alone. They behave differently, free liquidity is available now, reallocatable liquidity depends on an allocator acting, and a borrower sizing a draw needs to know which is which.
supplyingVaults is tiered. Lists carry the identity fields (everything /morphoCache/lite published, plus ids); the detail endpoint and ?expand=supplyingVaults carry every field. Expanded fields are omitted rather than nulled, so 'cap' in vault distinguishes "not asked for" from "no cap set".
vaultCaps is not supplyingVaults. It is what a public allocator could move, which is the number that decides whether a large borrow can be filled.
GET /v1/yields/borrow/markets/{network}/{marketId}/allocations
Portfolio
Wallet-scoped reads. Every response carries errors.unsupportedNetworks naming any chain we could not see, for a balance figure that matters more than anywhere else in the API.
/portfolio/summary/{address}
3
Everything below, in one call
/portfolio/positions/{address}
2
Vault positions across networks
/portfolio/positions/{address}/{network}/{vaultId}
2
One position
/portfolio/borrow-positions/{address}
2
Collateral, debt, LTV, health factor
/portfolio/total-returns/{address}/{network}/{vaultId}
2
Lifetime realised + unrealised return
/portfolio/partial-returns/{address}/{network}/{vaultId}
2
Return between two timestamps
/portfolio/historical-positions/{address}
2
Every vault ever held, including exited
/portfolio/historical-balances/{address}/{timestamp}
2
Balances reconstructed at a past date
/portfolio/idle-assets/{address}
2
Holdings not deployed anywhere we index
/portfolio/best-vault/{address}
3
Best vault per idle asset
/portfolio/best-deposit-options/{address}
3
Top N vaults per idle asset
Shared portfolio parameters
address
path
✅
Wallet address.
page, perPage
integer
–
Default 1 / 50, max 500.
allowedNetworks
csv
–
Slugs or chain ids.
allowedAssets
csv
–
Symbols or addresses.
minUsdValueThreshold
number
–
Default 0.01. Suppresses dust — a wallet that ever touched a vault keeps a rounding-dust position forever.
GET /v1/yields/portfolio/summary/{address}
Replaces roughly five separate requests, and is priced accordingly.
An average health factor would hide one position about to be liquidated behind several safe ones, so the lowest is reported instead.
GET /v1/yields/portfolio/positions/{address}
Response — list envelope of positions.
GET /v1/yields/portfolio/positions/{address}/{network}/{vaultId}
One position object as above. 404 when the wallet holds nothing in that vault.
GET /v1/yields/portfolio/borrow-positions/{address}
The indexer models collateral and debt as separate rows; they are re-joined here so a position is one object, not two halves.
healthFactor is collateral × liquidation threshold ÷ debt. It is null with no debt — a position that cannot be liquidated has no health factor, and returning Infinity would force every caller to special-case it.
GET /v1/yields/portfolio/total-returns/{address}/{network}/{vaultId}
Current value plus everything withdrawn minus everything deposited, denominated in the vault asset — a USD figure would conflate yield with the asset's own price movement.
GET /v1/yields/portfolio/partial-returns/{address}/{network}/{vaultId}
Period performance rather than lifetime. Contributions inside the window are subtracted, so a mid-window deposit does not read as a gain.
Request — fromTimestamp and toTimestamp are both required (a period return needs a period); toTimestamp must be after fromTimestamp. Either omitted, or reversed, is a 400.
closingValueIsCurrent is stated rather than implied: a toTimestamp in the past cannot be honoured exactly, because we hold no historical share price for every vault. The closing value is the current balance.
GET /v1/yields/portfolio/historical-positions/{address}
Every vault the wallet has ever held, including fully-exited ones, with when each opened and last saw activity. positions only shows current holdings, so a wallet that exited last month vanishes from it entirely.
Request — the shared portfolio parameters plus fromTimestamp, toTimestamp, eventType, and includeClosed (default true).
GET /v1/yields/portfolio/historical-balances/{address}/{timestamp}
Replayed from the transfer stream: Σdeposits − Σwithdrawals up to that instant.
Request: timestamp is a path parameter in unix seconds; non-numeric or non-positive is a 400.
It reports net contributed, not position value — yield accrued between events is not recoverable from transfers alone. Both limits are on the response rather than in a footnote.
GET /v1/yields/portfolio/idle-assets/{address}
Wallet balances not deployed into anything we index.
Request
address
path
✅
Wallet address.
page, perPage
integer
–
Default 1 / 50, max 200.
allowedNetworks
csv
–
Slugs or chain ids.
allowedAssets / disallowedAssets
csv
–
Symbols or addresses.
minUsdValueThreshold
number
–
Default 1 — below that, gas exceeds the yield.
What the scope actually is. Balances are read against a curated asset universe — every asset our vaults and markets use, plus the chain's native token and a short extras list. It is not every ERC-20 in the wallet.
That is a deliberate trade: an open scan needs a token indexer we do not run on Ethereum or Base, and it surfaces airdropped spam with fabricated prices, which in a "here is what you could be earning" endpoint is actively harmful. The consequence is that a holding outside the universe will not appear. "Idle" is also relative to what we index — a token deployed in a protocol we do not cover reads as idle here.
GET /v1/yields/portfolio/best-vault/{address}
Highest-yielding vault for each idle asset, with projected annual earnings on that balance. Restricted to vaults denominated in the same asset — a recommendation that silently requires a swap would be misleading.
Request: the idle-asset parameters plus:
apyInterval
enum
–
Window to rank on. Default 1day.
minTvl
number
–
Only consider vaults above this TVL, USD.
maxVaultsPerAsset
integer
–
Default 3, max 10. Used by best-deposit-options.
alwaysReturnAssets
boolean
–
Default false. Keep assets with no matching vault instead of dropping them.
GET /v1/yields/portfolio/best-deposit-options/{address}
Same request and shape, but each entry carries a vaults array of up to maxVaultsPerAsset options instead of a single vault.
projectedUsdAnnualEarnings is the point: an APY alone does not tell a user whether moving $40 is worth the gas.
Transactions
A wallet's on-chain activity against everything we index — the feed a portfolio UI renders as a history tab. The separate /liquidations API is market-scoped: it answers "what was liquidated in this market", not "what happened to me".
/portfolio/events/{address}
3
Every event against this wallet
/portfolio/events/{address}/{network}/{vaultId}
2
Events for one vault
GET /v1/yields/portfolio/events/{address}
Deposits, withdrawals, borrows, repayments and liquidations, newest first.
Request
address
path
✅
Wallet address.
eventType
string
–
deposit, withdraw, borrow, repay, liquidation
fromTimestamp / toTimestamp
integer
–
Unix seconds.
includeClosed
boolean
–
Default true.
Plus the shared portfolio parameters.
Response
A liquidation carries an extra block:
GET /v1/yields/portfolio/events/{address}/{network}/{vaultId}
The same feed, scoped to one vault. Same parameters, same event shape.
Historical
Every route takes an explicit window and an optional granularity. This replaces the legacy timeRange=1M enum, which cannot express "since I deposited" — the range a portfolio UI actually needs.
/historical/{network}/{vaultId}
2
TVL, APY, liquidity and implied asset price in one series
/historical/{network}/{vaultId}/apy
2
APY only
/historical/{network}/{vaultId}/tvl
2
TVL only
/historical/{network}/{vaultId}/share-price
3
Assets per share over time
/historical/{network}/{vaultId}/daily-flows
3
Net deposits and withdrawals per day
/historical/asset-prices/{network}/{address}
3
Asset price over time
/historical/borrow/{network}/{marketId}
2
Market supply, borrow, rates, utilization
Shared parameters
fromTimestamp
integer
–
Start of the window, unix seconds, inclusive.
toTimestamp
integer
–
End of the window, unix seconds, inclusive.
granularity
enum
–
1hour | 1day | 1week. Omit for the raw series.
page
integer
–
Default 1.
perPage
integer
–
Default 500, max 1000.
Buckets are aligned to the epoch and keep their closing value. These are point-in-time readings, so averaging within a bucket would invent a number that never existed at any instant.
GET /v1/yields/historical/{network}/{vaultId}
404 when we hold no history for that vault.
GET /v1/yields/historical/{network}/{vaultId}/apy
GET /v1/yields/historical/{network}/{vaultId}/tvl
GET /v1/yields/historical/{network}/{vaultId}/share-price
Requires indexed share supply.
On Ethereum and Base it returns an empty series with an explicit unavailableReason and the network in errors.unsupportedNetworks, rather than an empty array that reads like "this vault has no history".
GET /v1/yields/historical/{network}/{vaultId}/daily-flows
Net flow per day, counted from actual transfers.
Counted from transfers rather than differenced from TVL: a TVL delta conflates flows with yield accrual and price movement, so a vault that took no deposits but whose asset appreciated would show a fabricated inflow. Requires an indexer.
GET /v1/yields/historical/asset-prices/{network}/{address}
Two sources, named so you can tell them apart — they have different accuracy:
recorded— read from the daily price snapshots. Authoritative, and covers every asset we index including collateral assets no vault is denominated in.implied— derived from a vault's own history, where each point's USD and native totals give the price the pipeline observed. Used for the period before daily recording began, withsourceVaultnaming the vault it came from.
404 when the asset is neither recorded nor held by any indexed vault.
GET /v1/yields/historical/borrow/{network}/{marketId}
Realtime
Uncached on-chain reads, for when a cache is not good enough — sizing a liquidation, or reconciling against chain state.
/realtime/{network}/{vaultId}
3
Total assets, total supply and share price from ONE block
/realtime/{network}/{vaultId}/share-price
3
Share price alone
/realtime/{network}/{vaultId}/total-assets
3
Total assets alone
/realtime/{network}/{vaultId}/total-supply
3
Total share supply alone
/realtime/{network}/{vaultId}/underlying-asset-price
3
Asset identity live; price from the cache
GET /v1/yields/realtime/{network}/{vaultId}
Request: network and vaultId path parameters. No query parameters.
Prefer this route if you need more than one value. It is one RPC round-trip instead of several and more importantly the values come from the same block. Four separate calls can straddle a block and produce a share price that never existed. The combined route costs the same as a single sub-resource, so taking the consistent path is never penalised.
sharePrice is null, never 1.0, for a vault with no shares outstanding: 1.0 is a plausible-looking reading and would be indistinguishable from a real one.
The single-value routes
Each reads the same block and returns one slice of the snapshot above.
GET /v1/yields/realtime/{network}/{vaultId}/share-price
{ vaultId, readAt, sharePrice, asset } — asset is the symbol here, not the object
GET /v1/yields/realtime/{network}/{vaultId}/total-assets
{ vaultId, readAt, totalAssets: { native, usd } }
GET /v1/yields/realtime/{network}/{vaultId}/total-supply
{ vaultId, readAt, totalSupply }
They cost the same as the combined route, so there is no saving in asking for one value at a time — only the risk of straddling a block.
GET /v1/yields/realtime/{network}/{vaultId}/underlying-asset-price
Only the asset identity is read on-chain. The price comes from the same pricing layer the cached endpoints use, and priceSource says so — a caller reconciling against chain data needs to know which half is live.
Liquidations
GET /liquidations/overview-data?chainId={chainId}&marketId={marketId}
Aggregate summary across all matching positions (counts + USD totals).
GET /liquidations/positions?chainId={chainId}&marketId={marketId}
Paginated list of open borrow positions and their risk of liquidation (LTVs, HFs and more).
GET /liquidations/liquidated-positions?chainId={chainId}&marketId={marketId}
Paginated history of positions that have already been liquidated (most recent first).
Supported protocols, and chains
Protocols
Morpho
Vaults + lending markets
V1.1, V2
✅
✅
✅
✅
✅
✅
Chains
Every endpoint takes a chainId query param. Omit it and it defaults to Plume (98866). Unsupported chains return an empty result, not an error.
This is a list of Chains and their respective chainId below.
Plume
98866
Flare
14
Citrea
4114
Ethereum
1
Base
8453
Errors
400
Unknown query parameter, wrong type, or a missing required one (e.g. partial-returns without both timestamps)
Fix the request. The message names the offending property.
401
Missing, invalid, disabled or expired API key
Check the x-api-key header.
402
Monthly credit allowance exhausted, on a key with a hard cap
Upgrade the plan or ask support to raise the ceiling. Only keys explicitly opted into a spend ceiling can hit this — the default is that overage is billed.
404
Resource does not exist, or no history for it
Do not retry. Never returned as 200 null.
429
Over your plan's requests/second
Back off for Retry-After seconds.
5xx
Our problem
Retry with backoff; contact support if it persists.
What is not an error
Three things that look like failures and are not:
Unresolvable filter values. ?allowedNetworks=plume,atlantis returns 200 with every Plume result and errors.unsupportedNetworks: ["atlantis"]. Losing nine good networks to one typo would be worse than the warning.
Null values. priceUsd: null, apy["30day"]: null, healthFactor: null and sharePrice: null are all deliberate. They mean "we do not know" or "not applicable".
Last updated